183

探し回ったのですが、可能かどうかわかりませんでした。

私はこのMySQLクエリを持っています:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8)

フィールドIDには「一意のインデックス」があるため、2つにすることはできません。同じIDがデータベースにすでに存在する場合は、それを更新したいと思います。しかし、実際には、次のように、これらすべてのフィールドを再度指定する必要がありますか?

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY UPDATE a=2,b=3,c=4,d=5,e=6,f=7,g=8

または:

INSERT INTO table (id,a,b,c,d,e,f,g) VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY UPDATE a=VALUES(a),b=VALUES(b),c=VALUES(c),d=VALUES(d),e=VALUES(e),f=VALUES(f),g=VALUES(g)

私はすでに挿入物にすべてを指定しました...

補足として、回避策を使用してIDを取得したいと思います。

id=LAST_INSERT_ID(id)

誰かが私に最も効率的な方法が何であるかを教えてくれることを願っています。

4

9 に答える 9

97

このUPDATEステートメントは、古いフィールドを新しい値に更新できるようにするために提供されています。古い値が新しい値と同じである場合、どのような場合でも更新する必要があるのはなぜですか?

たとえば。列agすでに;に設定され2ている場合。8再更新する必要はありません。

または、次を使用することもできます。

INSERT INTO table (id,a,b,c,d,e,f,g)
VALUES (1,2,3,4,5,6,7,8) 
ON DUPLICATE KEY
    UPDATE a=a, b=b, c=c, d=d, e=e, f=f, g=g;

から取得するにidLAST_INSERT_ID; 同じために使用しているバックエンドアプリを指定する必要があります。

LuaSQLの場合、conn:getlastautoid()フェッチは値をフェッチします。

于 2013-01-17T16:26:58.667 に答える
48

あなたが望むかもしれないSQLへのMySQL固有の拡張があります-REPLACE INTO

ただし、「ONDUPLICATEUPDATE」とはまったく同じようには機能しません。

  1. 新しい行と衝突する古い行を削除してから、新しい行を挿入します。テーブルに主キーがない限り問題ありませんが、ある場合は、他のテーブルがその主キーを参照している場合

  2. 古い行の値を参照できないため、同等の処理を実行できません

    INSERT INTO mytable (id, a, b, c) values ( 1, 2, 3, 4) 
    ON DUPLICATE KEY UPDATE
    id=1, a=2, b=3, c=c + 1;
    

回避策を使用してIDを取得したいと思います!

これは機能するはずです—主キーが自動インクリメントである限り、last_insert_id()は正しい値を持つ必要があります。

ただし、前述したように、他のテーブルでその主キーを実際に使用するとREPLACE INTO、一意のキーを介して衝突した古い行が削除されるため、おそらく受け入れられません。

あなたがすることによっていくつかのタイピングを減らすことができる前に、他の誰かが提案しました:

INSERT INTO `tableName` (`a`,`b`,`c`) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE `a`=VALUES(`a`), `b`=VALUES(`b`), `c`=VALUES(`c`);
于 2013-01-17T16:38:46.120 に答える
26

これがあなたの問題の解決策です:

私はあなたのような問題を解決しようとしました、そして私は単純な側面からテストすることを提案したいと思います。

次の手順に従います。簡単な解決策から学びます。

手順1:次のSQLクエリを使用してテーブルスキーマを作成します。

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(30) NOT NULL,
  `password` varchar(32) NOT NULL,
  `status` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `no_duplicate` (`username`,`password`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;

データを含むテーブル<code>user</ code>

手順2:次のSQLクエリを使用して、データの重複を防ぐために2列のインデックスを作成します。

ALTER TABLE `user` ADD INDEX no_duplicate (`username`, `password`);

または、次のよう にGUIから2列のインデックスを作成します。GUIからインデックスを作成する インデックスを作成する列を選択します テーブル<code>user</code>のインデックス

ステップ3:存在する場合は更新し、次のクエリを使用しない場合は挿入します。

INSERT INTO `user`(`username`, `password`) VALUES ('ersks','Nepal') ON DUPLICATE KEY UPDATE `username`='master',`password`='Nepal';

INSERT INTO `user`(`username`, `password`) VALUES ('master','Nepal') ON DUPLICATE KEY UPDATE `username`='ersks',`password`='Nepal';

上記のクエリを実行した後のテーブル<code>user</ code>

于 2016-02-03T03:42:01.607 に答える
25

他に方法はありません。すべてを2回指定する必要があります。最初は挿入、2番目は更新の場合です。

于 2013-01-18T11:52:23.880 に答える
12

スクリプト言語を使用してSQLクエリを準備できる場合に備えて、SETの代わりにを使用してfield=valueのペアを再利用できます(a,b,c) VALUES(a,b,c)

PHPの例:

$pairs = "a=$a,b=$b,c=$c";
$query = "INSERT INTO $table SET $pairs ON DUPLICATE KEY UPDATE $pairs";

表の例:

CREATE TABLE IF NOT EXISTS `tester` (
  `a` int(11) NOT NULL,
  `b` varchar(50) NOT NULL,
  `c` text NOT NULL,
  UNIQUE KEY `a` (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
于 2016-12-06T17:23:31.580 に答える
7

構文の使用を検討することもできますが、 PRIMARYREPLACE INTO / UNIQUEキーが重複すると、行が削除され、新しい行が挿入されることに注意してください。

すべてのフィールドを再指定する必要はありません。ただし、パフォーマンスの低下の可能性を考慮する必要があります(テーブルの設計によって異なります)。

警告:

  • AUTO_INCREMENT主キーがある場合は、新しいキーが与えられます
  • インデックスはおそらく更新する必要があります
于 2015-10-07T11:07:00.490 に答える
7

遅いことは知っていますが、誰かがこの答えを手伝ってくれることを願っています

INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);

以下のチュートリアルをここで読むことができます:

https://mariadb.com/kb/en/library/insert-on-duplicate-key-update/

http://www.mysqltutorial.org/mysql-insert-or-update-on-duplicate-key-update/

于 2019-03-20T07:47:45.740 に答える
0

MySQL v8.0.19以降では、これを行うことができます: mysql doc

INSERT INTO mytable(fielda, fieldb, fieldc) 
VALUES("2022-01-01", 97, "hello") 
AS NEW(newfielda, newfieldb, newfieldc) 
ON DUPLICATE KEY UPDATE
fielda=newfielda,
fieldb=newfieldb,
fieldc=newfieldc;


補足:また、重複キー更新部分で条件付きが必要な場合は、MySQLにひねりがあります。fieldaを最初の引数として更新し、それをfieldbのIF句内に含めると、すでに新しい値に更新されています。最後まで動かしてください。fieldaが例のような日付であり、日付が前の日付よりも新しい場合にのみ更新するとします。

INSERT INTO mytable(fielda, fieldb) 
VALUES("2022-01-01", 97) 
AS NEW(newfielda, newfieldb, newfieldc) 
ON DUPLICATE KEY UPDATE
fielda=IF(fielda<STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfielda,fielda),
fieldb=IF(fielda<STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfieldb,fieldb);

この場合、 <!のため、fieldbは更新されません。fieldaの更新をその下に移動するか、<=または= ...で確認する必要があります!

INSERT INTO mytable(fielda, fieldb) 
VALUES("2022-01-01", 97) 
AS NEW(newfielda, newfieldb, newfieldc) 
ON DUPLICATE KEY UPDATE
fielda=IF(fielda<STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfielda,fielda),
fieldb=IF(fielda=STR_TO_DATE(newfielda,'%Y-%m-%d %H:%i:%s'),newfieldb,fieldb);

これは、=を使用すると期待どおりに機能します。これは、fieldaがfieldbのif句に到達する前に、すでに新しい値に更新されているためです。

于 2022-02-18T14:31:18.340 に答える
-9

このような場合はinsertignoreを使用できます。重複するレコードを取得した場合は無視されますINSERTIGNORE...; --ONDUPLICATEKEYなし

于 2015-07-08T09:44:50.923 に答える