Mysql 5.5には、「イベント」に関する情報を格納するテーブルがあります。時系列順にするために、前のイベントと次のイベントを参照する2つの列を作成しました。そこで、同じテーブルの主キーを参照する2つの外部キーを作成しました。行が発生順に最初の場合、前の要素の値はnullになります。
だから、私のテーブルは:
calendars
--------
calendar_id (PRIMARY KEY)
calendar_prev
calendar_next
other columns...
私はこのデータを持っています(例として)
+--------------+---------------+---------------+
| calendar_id | calendar_prev | calendar_next |
+--------------+---------------+---------------+
| 1 | NULL | 2 |
| 2 | 1 | 3 |
| 3 | 2 | 4 |
| 4 | 3 | 5 |
| 5 | 4 | NULL |
+--------------+---------------+---------------+
そしてこれらの外部キー。
ALTER TABLE `calendars`
ADD CONSTRAINT `calendars_ibfk_3` FOREIGN KEY (`calendar_next`) REFERENCES `calendars` (`calendar_id`) ON DELETE SET NULL ON UPDATE CASCADE,
ADD CONSTRAINT `calendars_ibfk_2` FOREIGN KEY (`calendar_prev`) REFERENCES `calendars` (`calendar_id`) ON DELETE SET NULL ON UPDATE CASCADE;
これは私のサーバーとsqlfiddleで正常に動作します。
要素のIDを変更しようとすると、問題が発生します。外部キーの動作について何か見落としがない場合、calendar_id 5を編集して、たとえば7に設定すると、calendar_id = 4の行でもcalendar_nextの値が5から7に変更されます。ただし、iエラーが発生するだけです。言い換えれば、私がこれを試した場合:
UPDATE `calendars` SET `calendar_id` = 7 WHERE `calendar_id` = 5;
私はこのエラーを受け取ります:
Cannot delete or update a parent row: a foreign key constraint fails (`db_2_813f44`.`calendars`, CONSTRAINT `calendars_ibfk_3` FOREIGN KEY (`calendar_next`) REFERENCES `calendars` (`calendar_id`) ON DELETE SET NULL ON UPDATE CASCADE):
私は自分が間違っていることを本当に理解できません。
問題の原因を特定しました。可能な回避策は、リンクリスト用に別のテーブルを作成することです。
CREATE TABLE calendars
( calendar_id INT PRIMARY KEY
-- other columns
) ;
CREATE TABLE calendar_list
( calendar_id INT NOT NULL
, calendar_next INT NOT NULL
, PRIMARY KEY (calendar_id)
, UNIQUE (calendar_next)
, CONSTRAINT calendar_list_1
FOREIGN KEY (calendar_id)
REFERENCES calendars (calendar_id)
ON DELETE CASCADE ON UPDATE CASCADE
, CONSTRAINT calendar_list_2
FOREIGN KEY (calendar_next)
REFERENCES calendars (calendar_id)
ON DELETE CASCADE ON UPDATE CASCADE
) ;
次のクエリを使用して、現在のクエリを表示できます。
SELECT c.calendar_id,
prev.calendar_id AS calendar_prev,
next.calendar_next
FROM calendars AS c
LEFT JOIN calendar_list AS prev
ON c.calendar_id = prev.calendar_next
LEFT JOIN calendar_list AS next
ON c.calendar_id = next.calendar_id ;
UPDATE
はこの設定で正常に動作します。 SQL-Fiddleでテストします。 (削除は別の問題になりますが、以前のデザインでも対処されていませんでした。削除が最初または最後のポイント以外のどこかにある場合、nullに設定するとリストが壊れます。)