4

私の問題は、失敗した挿入で MySQL 自動インクリメントが増加するのはなぜですか? id、しかし、フィールドを増やす代わりに、INSERT問題を引き起こしているクエリを書き直すことをお勧めします。と の 2 つのフィールドを持つデータベースがあるとしますidusernameここidで、 は主キーで、usernameは一意のキーです。私は本質的にそれを行う構文を探していますINSERT...IF NOT EXISTS。今、私はそうします

INSERT INTO `table`(`username`) 
    VALUES ('foo') 
    ON DUPLICATE KEY UPDATE `id`=`id`

データベースに書き込むスレッドは 1 つだけなので、同時実行保護は必要ありません。提案?

4

5 に答える 5

6

これを使用する必要があります:

INSERT INTO tableX (username) 
  SELECT 'foo' AS username
  FROM dual
  WHERE NOT EXISTS
        ( SELECT *
          FROM tableX 
          WHERE username = 'foo'
        ) ;

より多くの列の値を含める場合:

INSERT INTO tableX (username, dateColumn) 
  SELECT 'foo'                       --- the aliases are not needed             
       , NOW()                       --- actually
  FROM dual
  WHERE NOT EXISTS
        ( SELECT *
          FROM tableX 
          WHERE username = 'foo'
        ) ;                      
于 2012-05-15T12:21:19.553 に答える
4

リンク先の質問への回答に記載されている理由により、カウンターがインクリメントされるのを防ぐことはできないと思います。

次の 3 つのオプションがあります。

  1. スキップされた識別子で生きます。本当に64ビットを使い果たすと思いますか?

  2. 次の操作を試みる前に、既存のレコードの存在を確認してくださいINSERT

    DELIMITER ;;
    
    IF NOT EXISTS (SELECT * FROM `table` WHERE username = 'foo') THEN
      INSERT INTO `table` (username) VALUES ('foo');
    END IF;;
    
    DELIMITER ;
    

    または、FROM dual WHERE NOT EXISTS ...@ypercube によって提案されたフォームを使用することをお勧めします。

  3. 各挿入後にカウンターをリセットします。INSERTストアド プロシージャ内で操作を実行する場合は、重複キー エラーのハンドラーを使用してこれを行うことができます。

    DELIMITER ;;
    
    CREATE PROCEDURE TEST(IN uname CHAR(16) CHARSET latin1) BEGIN
      DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' BEGIN
        -- WARNING: THIS IS NOT SAFE FOR CONCURRENT CONNECTIONS
        SET @qry = CONCAT(
          'ALTER TABLE `table` AUTO_INCREMENT = ',
          (SELECT MAX(id) FROM `table`)
        );
        PREPARE stmt FROM @qry;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @qry = NULL;
      END;
      INSERT INTO `table` (username) VALUES (uname);
    END;;
    DELIMITER ;
    

    この戦略に関する以下のコメントで@ypercubeが提起した(有効な)懸念を念頭に置いて、代わりに次を使用できます。

    SELECT AUTO_INCREMENT - 1
    FROM   INFORMATION_SCHEMA.TABLES
    WHERE  table_schema = 'db_name' AND table_name = 'table';
    
于 2012-05-15T12:21:56.853 に答える
2

挿入が失敗した後、自動インクリメントフィールドをリセットするだけです

ALTER TABLE テーブル名 AUTO_INCREMENT =1;

これは自動インクリメントを 1 にリセットしませんが、現在の最大値に 1 を加えた値にリセットします。

また、DB に接続しているユーザーには、ターゲット テーブルに対する変更権限が必要です。

于 2015-03-25T21:15:12.457 に答える
0

そのユーザーが以前に挿入されていた場合は、そのユーザーを挿入する前に確認することもできます。DB への追加の呼び出しが発生しますが、ユーザーが既に存在する場合は、見つけた情報を返すことができ、偽の挿入が回避されます。

于 2014-11-06T13:26:34.553 に答える
-1

使用してINSERT IGNORE INTO tableください。以下の投稿を確認してください

http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html

次のようにできます。

INSERT INTO `table`(`username`) 
VALUES ('foo')      
ON DUPLICATE KEY UPDATE `username`= 'foo' 

また

INSERT IGNORE INTO `table`
SET `username` = 'foo'
于 2012-05-15T11:48:42.813 に答える