2011-01-01 71 views
14

で行を削除する私が定義は次のようであるMySQLのテーブルがあります。自己参照外部キー

 
CREATE TABLE `guestbook` (
    `Id` int(10) unsigned NOT NULL, 
    `ThreadId` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`Id`), 
    KEY `ThreadId` (`ThreadId`), 
    CONSTRAINT `guestbook_ibfk_1` FOREIGN KEY (`ThreadId`) REFERENCES `guestbook` (`Id`) 
) ENGINE=InnoDB; 

を、現在唯一の1行がテーブルにあります:

 
mysql> select * from guestbook; 
+-----+----------+ 
| Id | ThreadId | 
+-----+----------+ 
| 211 |  211 | 
+-----+----------+ 

問題制約を破ることなくこの行を削除する方法がないということです。

 
mysql> delete from guestBook; 
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`polaris`.`guestbook`, CONSTRAINT `guestbook_ibfk_1` FOREIGN KEY (`ThreadId`) REFERENCES `guestbook` (`Id`)) 

ThreadId列がnullでないと定義されているため、ThreadIdを一時的に別の値に設定して行を削除することもできません。テーブルの定義を変更したり、テーブル全体を削除せずに行を削除する方法はありますか?

+1

行自体が子行である行が奇妙です。 – Chandu

+4

うわー、それはあなたが最後の行を削除するために制約をオフにする必要がある行を持っているテーブル構造を作成しました。あまりにもIDが22ではありませんでした。 –

+0

@Conrad:ええ、これはいつも自己参照する外部キーで起こります。 :$ –

答えて

19

あなたは一時的にこのクエリを使用して外部キー制約を無効にすることができます

SET foreign_key_checks = 0; 
+0

ありがとう、これは今のところ最良の方法だと思われます。 –

+0

このクエリはどこで実行されるべきですか?どのテーブルにどのように?あなたはあなたの答えをよりよく編集し、より明確にする方がよいでしょう。 – Trix

0

雅を一時的にいくつかの回避策があります

set foreign_key_checks=0; 
+0

はforeign_key_checksではなくforeign_key_constraintsのように見えます。 :) –

5

外部キーを無効にします。他の人が提案するアプローチ...

SET foreign_key_checks = 0; 

...すべてのテーブルの外部キーを無効にします。これは、共有環境での使用には適していません。

別のアプローチは、私たちは、DMLを使用してデータを整理して、使用して外部キーを回復することができます

ALTER TABLE `guestbook` 
    DROP FOREIGN KEY `guestbook_ibfk_1` 
/

を使用して外部キーをドロップすることです:

ALTER TABLE `guestbook` 
    ADD CONSTRAINT `guestbook_ibfk_1` FOREIGN KEY (`ThreadId`) 
     REFERENCES `guestbook` (`Id`) 
/

しかしへの道がありますDDLを実行せずにデータを変更しますか?さて、私たちは、新しいレコードを挿入し、それを参照するために現在のレコードを変更することができます。

INSERT INTO `guestbook` VALUES (212, 211) 
/
UPDATE `guestbook` 
SET `ThreadId` = 212 
WHERE `Id` = 211 
/

賢明なオブザーバーは、我々はまだレコードのみの間で、共同の依存関係になってしまっていることに気づいただろう。だから私たちは本当に進んでいません。 1つではなく2つのレコードを削除できます。 (ちなみに、これは、外部キーが削除または無効になっている間に実行するDMLに適用されます)。だから、おそらく我々はデータモデルを再考する必要があります。循環依存関係や階層を持つグラフをモデル化していますか?

階層データ構造には、少なくとも1つのルートノードが必要です。ルートノードは、他のレコードが依存するレコードですが、レコード自体に依存しないレコードです。これを実装する通常の方法は、外部キー列をオプションにすることです。階層の最上位レベルでは、レコードはその列にNULLを持つ必要があります。そのようなルートノードが1つだけあるべきかどうか、あるいはいくつかが許可されるかどうかは、ビジネスルールの問題です。

ALTER TABLE `guestbook` MODIFY `ThreadId` int(10) unsigned 
/

モデリングの用語では、これは独自のマスタであるレコードとは異なりませんが、より直観的な解決策です。

3

自己参照行を削除できないというのは、長年のknown bug/outstanding feature request in MySQLです。

多くの状況では、この問題に対して擦り付けを行うと、削除を実行する前に外部キーをNULLにすることができます。回避策は、目的の行のみに影響します(同じWHERE句を使用します)。

0

私の外部キーにON DELETE SET NULLを設定すると、自己参照を削除します。 ON DELETEを指定しないと、MySQLのデフォルトはRESTRICTになります。

もちろん、列がNULLABLEであることを確認してください。デフォルトの設定に応じてSET DEFAULTを試すこともできます。しかし、NO ACTIONがMySQLのRESTRICTのエイリアスに過ぎないことを覚えておいてください!

MySQL 5.6でのみテストされました(この質問が最初に投稿されたときにはリリースされませんでした)。

3

外部キーにON DELETE CASCADEアクションを追加すると、自己参照型の行を削除できます。

CONSTRAINT `guestbook_ibfk_1` FOREIGN KEY (`ThreadId`) REFERENCES `guestbook` (`Id`) ON DELETE CASCADE 

これはON DELETE SET NULLを使用してより優れている利点は、あなたが「スレッドID」列のNULL可能を作るためにあなたのスキーマを変更する必要がないことです。

+0

私はこの答えが最高で正しい答えではない理由を理解していません。 – RusAlex

関連する問題