sql >> データベース >  >> RDS >> Mysql

MySQLのINSERTIGNOREINTOと外部キー

    [新しい回答]

    これを提起してくれた@NeverEndingQueueに感謝します。 MySQLがついにこの問題を修正したようです。この問題が最初に修正されたバージョンはわかりませんが、現在、次のバージョンでテストしたところ、問題は発生していません。

    mysql> SHOW VARIABLES LIKE "%version%";
    +-------------------------+------------------------------+
    | Variable_name           | Value                        |
    +-------------------------+------------------------------+
    | innodb_version          | 5.7.22                       |
    | protocol_version        | 10                           |
    | slave_type_conversions  |                              |
    | tls_version             | TLSv1,TLSv1.1                |
    | version                 | 5.7.22                       |
    | version_comment         | MySQL Community Server (GPL) |
    | version_compile_machine | x86_64                       |
    | version_compile_os      | Linux                        |
    +-------------------------+------------------------------+
    

    明確にするために:

    mysql> INSERT IGNORE INTO child
        -> VALUES
        ->     (NULL, 1)
        ->     , (NULL, 2)
        ->     , (NULL, 3)
        ->     , (NULL, 4)
        ->     , (NULL, 5)
        ->     , (NULL, 6);
    Query OK, 4 rows affected, 2 warnings (0.03 sec)
    Records: 6  Duplicates: 2  Warnings: 2
    

    この最後のクエリの意味と、問題が修正されたことを示す理由をよりよく理解するには、以下の古い回答を続けてください。

    [古い答え]

    私の解決策は問題の回避策であり、実際の解決策は常にMySQL自体の中で問題を修正することです。

    次の手順で問題が解決しました:

    a。 次のテーブルとデータを用意することを検討してください。

    mysql>
    CREATE TABLE parent (id INT AUTO_INCREMENT NOT NULL
                         , PRIMARY KEY (id)
    ) ENGINE=INNODB;
    
    mysql>
    CREATE TABLE child (id INT AUTO_INCREMENT
                        , parent_id INT
                        , INDEX par_ind (parent_id)
                        , PRIMARY KEY (id)
                        , FOREIGN KEY (parent_id) REFERENCES parent(id)
                            ON DELETE CASCADE
                            ON UPDATE CASCADE
    ) ENGINE=INNODB;
    
    mysql>
    INSERT INTO parent
    VALUES (NULL), (NULL), (NULL), (NULL), (NULL), (NULL);
    
    mysql>
    SELECT * FROM parent;
    +----+
    | id |
    +----+
    |  1 |
    |  2 |
    |  3 |
    |  4 |
    |  5 |
    |  6 |
    +----+
    

    b。 次に、問題を示すためにいくつかの行を削除する必要があります。

    mysql>
    DELETE FROM parent WHERE id IN (3, 5);
    

    c。問題: 次の子行を挿入しようとすると、問題が発生します。

    mysql>
    INSERT IGNORE INTO child
    VALUES
        (NULL, 1)
        , (NULL, 2)
        , (NULL, 3)
        , (NULL, 4)
        , (NULL, 5)
        , (NULL, 6);
    
    ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint f
    ails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`parent_id`) REFERE
    NCES `parent` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)
    
    mysql>
    SELECT * FROM child;
    Empty set (0.00 sec)
    

    IGNORE キーワードが使用されますが、生成されたエラーが警告に変換されないため、MySQLは要求された操作をキャンセルします(想定どおり)。問題が明らかになったので、エラーに直面することなく、ステートメントへの最後の挿入を実行する方法を見てみましょう。

    d。解決策: 挿入されたレコードにもその数にも依存しない他の定数ステートメントによって、挿入をステートメントにラップします。

    mysql>
    SET FOREIGN_KEY_CHECKS = 0;
    
    mysql>
    INSERT INTO child
    VALUES
        (NULL, 1)
        , (NULL, 2)
        , (NULL, 3)
        , (NULL, 4)
        , (NULL, 5)
        , (NULL, 6);
    
    mysql>
    DELETE FROM child WHERE parent_id NOT IN (SELECT id FROM parent);
    
    mysql>
    SET FOREIGN_KEY_CHECKS = 1;
    

    これが最適ではないことは知っていますが、MySQLが問題を修正していない限り、これは私が知っている中で最高です。特に、PHPでmysqliライブラリを使用すると、すべてのステートメントを1つのリクエストで実行できるためです。



    1. pg_restoreの実行時に、ファイルヘッダーで[アーカイバ]のサポートされていないバージョン(1.13)を取得する

    2. PHP / MySQLでページビューをカウントする最良の方法は何ですか?

    3. 複数のコンシューマーを持つSQLテーブルとしてのジョブキュー(PostgreSQL)

    4. OracleのNANVL()関数