web-dev-qa-db-ja.com

MYSQL-同じテーブルの外部キーに関する問題

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):

私は自分が間違っていることを本当に理解できません。

4

問題の原因を特定しました。可能な回避策は、リンクリスト用に別のテーブルを作成することです。

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に設定するとリストが壊れます。)

2
ypercubeᵀᴹ