MySQL条件付き挿入


98

条件付きINSERTを作成するのが難しい

インスタンスIDが一意である列(インスタンス、ユーザー、アイテム)を持つx_tableがあります。ユーザーが特定のアイテムをまだ持っていない場合にのみ、新しい行を挿入します。

たとえば、instance = 919191 user = 123 item = 456を挿入しようとしています

Insert into x_table (instance, user, item) values (919191, 123, 456) 
    ONLY IF there are no rows where user=123 and item=456 

正しい方向への助けやガイダンスは大歓迎です。

回答:


115

挿入を実行するときに、DBMSが選択するテーブルに制限を課していない場合は、次のことを試してください。

INSERT INTO x_table(instance, user, item) 
    SELECT 919191, 123, 456
        FROM dual
        WHERE NOT EXISTS (SELECT * FROM x_table
                             WHERE user = 123 
                               AND item = 456)

これにdualは、1行のみのテーブルがあります(元はOracleにあり、現在はmysqlにもあります)。ロジックは、SELECTステートメントが必要な値を含む単一行のデータを生成するということですが、値がまだ見つからない場合に限られます。

または、MERGEステートメントを確認します。


1
dualこの場合、事前に作成する必要がありますか、それとも、クエリのみを使用するためにクエリによって作成される、ある種の特別な「一時」テーブルですか?
itsmequinn

8
dualまだ作成していない場合は、作成する必要があります。 CREATE TABLE dual ( dummy CHAR(1) DEFAULT 'x' NOT NULL CHECK (dummy = 'x') PRIMARY KEY ); INSERT INTO dual VALUES('x'); REVOKE ALL ON dual FROM PUBLIC; GRANT SELECT ON dual TO PUBLIC;
ジョナサンレフラー、2012

それを知って
本当に

11
MySQLでは、実際には「dual」というテーブルが存在する必要はありません。これは、そこから何かを選択するために使用できる特別なテーブル名です。
クリストファーシュルツ

3
MySQLは「デュアル」の概念を「尊重」しますが、実際には存在しません。たとえば、SELECT COUNT(*) FROM dual常に取得する1場合、およびSELECT 'foo' FROM dual常に取得する場合foo。しかし、それはできませんしSELECT * FROM dual、できませんDESCRIBE dual。まだ確認していませんが、に対する権限を取り消すこともできないと思いますdual。したがって、期待どおりに機能することを指摘しておく必要があります...機能しない場合を除き、;)
クリストファーシュルツ

52

INSERT IGNORE(user、item)に一意のインデックスがある場合、行を更新または挿入する代わりに、暗黙的に挿入を無視するwhichを使用することもできます。

クエリは次のようになります。

INSERT IGNORE INTO x_table(instance, user, item) VALUES (919191, 123, 456)

で一意のインデックスを追加できCREATE UNIQUE INDEX user_item ON x_table (user, item)ます。


2
MySQLのドキュメントごとに、INSERT IGNOREはREPLACEに対応するものです... INSERT IGNORE:古い行を保持します。REPLACE:新しい行を保持します。どちらも一意のキーで動作します。
ポールケンジョラ2015年

史上最高の答え
jmojico

30

そのようなことを試したことがありますか?

INSERT INTO x_table
SELECT 919191 as instance, 123 as user, 456 as item
FROM x_table
WHERE (user=123 and item=456)
HAVING COUNT(*) = 0;

ああそう!SELECTステートメントが1つだけのスマートで素晴らしいソリューション
java acm

いいね。これは、最初の試みでpostgresqlに対して機能しますが、受け入れられた回答は私には思われませんでした。
マイティパイル2017年

10

を使用してUNIQUE(user, item)、次の操作を行います。

Insert into x_table (instance, user, item) values (919191, 123, 456) 
  ON DUPLICATE KEY UPDATE user=123

このuser=123ビットは、ON DUPLICATE重複がある場合に実際には何もせずに句の構文に一致させる「no-op」です。


1
Unique(user、item)を設定できません。同じユーザーとアイテムを持つ複数のインスタンスが存在する可能性があるためです...この挿入を実行しているときではありません。
不明な

2

一意の制約を設定したくない場合、これはチャームのように機能します。

INSERT INTO `table` (`column1`, `column2`) SELECT 'value1', 'value2' FROM `table` WHERE `column1` = 'value1' AND `column2` = 'value2' HAVING COUNT(`column1`) = 0

それが役に立てば幸い !


2

あなたが欲しいのはINSERT INTO table (...) SELECT ... WHERE ...です。MySQL 5.6マニュアルから

あなたの場合それは:

INSERT INTO x_table (instance, user, item) SELECT 919191, 123, 456 
WHERE (SELECT COUNT(*) FROM x_table WHERE user=123 AND item=456) = 0

または、実行するかどうかを決定するために複雑なロジックを使用していないため、これら2つの列の組み合わせにキーをINSERT設定してUNIQUEを使用することもできますINSERT IGNORE


答えは出ましたか?引き続き取得ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where...(5.6.34を実行)
hlin117 '18 / 11/18

from dual前に言う必要があると思いますwhere
hlin117 2016年

@ hlin117 FROM DUALテーブルが参照されなかった場合、MariaDB ではデフォルトです(このドキュメントを参照)。
イエティ

1

(x_table.user、x_table.item)が一意であるという制約を追加すると、同じユーザーとアイテムで別の行を挿入すると失敗します。

例えば:

mysql> create table x_table ( instance integer primary key auto_increment, user integer, item integer, unique (user, item));
Query OK, 0 rows affected (0.00 sec)

mysql> insert into x_table (user, item) values (1,2),(3,4);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> insert into x_table (user, item) values (1,6);
Query OK, 1 row affected (0.00 sec)

mysql> insert into x_table (user, item) values (1,2);
ERROR 1062 (23000): Duplicate entry '1-2' for key 2

そうではありません。同じユーザーの行は複数存在できますが、ユーザーとアイテムのペアの行は複数存在できません。
Matthew Flaschen、2009年

ええ、ええ。読み間違えました。ペアに制約を加えるために編集されました。
NickZoic 2009年

いいコメント... mysql_query( "INSERT")を使用してPHPでクエリを実行し、またはそのままにしておきます。そのため、エラーについて警告するので、チェックを行う必要はありません
Angel.King.47

1

データを挿入する前に重複をチェックすることは良いことですが、重複したデータが誤って挿入されないように、列に一意の制約/インデックスを置くことをお勧めします。


1

次の解決策を使用して問題を解決できます。

INSERT INTO x_table(instance, user, item) 
    SELECT 919191, 123, 456
        FROM dual
        WHERE 123 NOT IN (SELECT user FROM x_table)

このコードは質問に答えることがありますが、問題を解決する方法および/または理由に関する追加のコンテキストを提供すると、回答の長期的な価値が向上します。
Nic3500

0

Alexの応答を少し変更して、既存の列の値を参照することもできます。

Insert into x_table (instance, user, item) values (919191, 123, 456) 
  ON DUPLICATE KEY UPDATE user=user

0

これはPostgreSQLの略です

INSERT INTO x_table
SELECT NewRow.*
FROM (SELECT 919191 as instance, 123 as user, 456 as item) AS NewRow
LEFT JOIN x_table
ON x_table.user = NewRow.user AND x_table.item = NewRow.item
WHERE x_table.instance IS NULL

-1
Insert into x_table (instance, user, item) values (919191, 123, 456) 
    where ((select count(*) from x_table where user=123 and item=456) = 0);

構文はDBによって異なる場合があります...


2
これは何のためですか?MySQL?
Umair A. 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.