質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Q&A

解決済

2回答

4839閲覧

外部キー制約を用いて、2つの列を外部参照したい

ShieNishikawa

総合スコア15

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

0グッド

0クリップ

投稿2021/11/08 11:22

編集2021/11/08 11:28

前提・実現したいこと

filesテーブルのuser_id列とuser_name列から、それぞれusersテーブルのid列とname列を参照したい。
files(子テーブル)     users(親テーブル)
・user_id(外部キー)    ・id(参照されるキー)
・user_name(外部キー)   ・name(参照されるキー)

発生している問題・エラーメッセージ

ERROR 3780 (HY000): Referencing column 'user_name' and referenced column 'name' in foreign key constraint 'files_ibfk_1' are incompatible.

該当のソースコード

sql

1CREATE TABLE files ( 2 id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, 3 user_id int unsigned, 4 user_name varchar(191) NULL, 5 FOREIGN KEY (user_id, user_name) 6 REFERENCES users(id,name) 7);

試したこと

mysql> SHOW CREATE TABLE users;
で調べてみると、
| users | CREATE TABLE users (
id int unsigned NOT NULL AUTO_INCREMENT,
name varchar(191) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
email varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
email_verified_at timestamp NULL DEFAULT NULL,
password varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
remember_token varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
created_at timestamp NULL DEFAULT NULL,
updated_at timestamp NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY users_email_unique (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |
でした。
usersテーブルのnameも、filesテーブルのuser_nameもvarchar(191)なのに、なぜ参照できないのでしょうか。

補足情報(FW/ツールのバージョンなど)

Laravel Framework 5.7.29
mysql Ver 8.0.23 for Linux on x86_64 (MySQL Community Server - GPL)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

usersテーブルのnameも、filesテーブルのuser_nameもvarchar(191)なのに、なぜ参照できないのでしょうか。

SQL

1FOREIGN KEY (user_id, user_name) 2 REFERENCES users(id,name)

上記で指定しているREFERENCES users(id,name)id,nameの項目のインデックスがusersでは定義されていないからでしょう。
13.1.17.2 外部キー制約の使用

ですが、usersに対して外部キー制約をするというなら、usersのprimaryKey(ID)に対して行うべきであり、そもそもfilesuser_nameという項目を持つべきではありません。

filesuser_nameという項目を持つというなら、それはfilesにデータを作成する際にusersを参照した結果というだけであり変更も可能なもので、外部キー制約するものではないのです。

投稿2021/11/08 12:23

sazi

総合スコア25327

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ShieNishikawa

2021/11/11 01:47 編集

id,nameの項目のインデックスを定義したら、外部キー制約できました。しかし、ウェブサイトのフォームからfileをpostしようとすると、「user_name dosen't exist」となりました。 なぜこのような構成にしようとしたかというと、fileをpostしたuserのsort機能を付けたかったからです。user_idでsortするとregisterした順に並んでしまうので、アルファベット順に並べるためにuser_nameという項目を設けてsortしようとしたのでした。そのためには、2つの組で外部キー制約するという方法しか思いつきませんでした。正規化していないおかしな構成でした。 結局、$user = Auth::user(); user_name = $user->name でユーザ名を取得することにしました。 浅はかな質問に丁寧に回答していただき、ありがとうございました。外部キー制約について大変勉強になりました。
sazi

2021/11/11 03:05

ソートするのが目的で、外部キー制約を付ける事などありません。 単にソート項目を指定すれば良いだけです。 ソートによる性能が問題なら、目的に応じたインデックスの追加を行います。 ただ、名称によるソートという事なら基本文字コードによるソートですので、意図した並びでない場合もあります。 照合順序も確認された方が良いかもしれません。 https://www.dbonline.jp/mysql/ini/index5.html
ShieNishikawa

2021/11/22 02:47

ありがとうございます。確認してみます。
guest

0

そもそも、なぜそのような構成が必要なのでしょうか?

正規化という観点から考えれば、user_idで紐付けることで、そこから名前は取り出せますので、user_nameまで関連付けるのは全く冗長なだけです。

投稿2021/11/08 12:02

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ShieNishikawa

2021/11/11 01:51 編集

fileをpostしたuserのsort機能を付けたかったからです。user_idでsortするとregisterした順に並んでしまうので、アルファベット順に並べるためにuser_nameという項目を設けてsortしようとしたのでした。そのためには、2つの組で外部キー制約するという方法しか思いつきませんでした。正規化していないおかしな構成でした。 結局、$user = Auth::user(); user_name = $user->name; でユーザ名を取得することにしました。 正規化について指摘していただき、ありがとうございました。
maisumakun

2021/11/11 01:56

> アルファベット順に並べるためにuser_nameという項目を設けてsortしようとしたのでした。そのためには、2つの組で外部キー制約するという方法しか思いつきませんでした。 JOINすれば、別テーブルを基準に並べ替えることも可能です。
ShieNishikawa

2021/11/22 02:48

ありがとうございます。検討してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問