web-dev-qa-db-ja.com

重複キー更新時に挿入と同じ

私は周りを検索しましたが、それが可能であるかどうかわかりませんでした。

私はこの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)

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

141
Roy

他に方法はありません、私はすべてを二度指定しなければなりません。最初は挿入用、次は更新用です。

21
Roy

UPDATEステートメントは、古いフィールドを新しい値に更新できるようにするために与えられています。古い値が新しい値と同じである場合、どうしてそれを更新する必要があるのでしょうか。

例えば。列aからgがすでに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;

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

LuaSQLでは、conn:getlastautoid()が値を取得します。

70
hjpotter92

MySQLに固有のSQLの拡張機能があり、それをあなたが望むものにすることができます - REPLACE INTO

しかし、それは 'ON DUPLICATE UPDATE'と全く同じようには動作しません。

  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`);
39
Danack

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

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

次の手順に従ってください:簡単な解決策から学んでください。

手順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;

A table <code>user</code> with data

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

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

または、次のようにGUIから2列のインデックスを作成します。 Create index from GUISelect columns to create indexIndexes of table <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';

Table <code>user</code> after running above query

21
user5505982

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

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;
7
Chris

REPLACE INTO構文の使用を検討したいかもしれませんが、PRIMARY/UNIQUEキーが重複している場合は、行を削除し、を新たに挿入します。

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

警告:

  • AUTO_INCREMENT主キーがある場合は、新しい主キーが与えられます
  • インデックスはおそらく更新する必要があるでしょう
4
code ninja

私はそれが遅れていることを知っています、しかし私は誰かがこの答えに助けられることを望みます

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/

1
Galang Piliang