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하나의 행만있는 테이블이 있습니다 (원래 Oracle에서 발견되었지만 현재는 mysql에서도 발견됨). 논리는 SELECT 문이 필요한 값이있는 단일 데이터 행을 생성하지만 값이 아직 발견되지 않은 경우에만 생성된다는 것입니다.

또는 MERGE 문을보십시오.


1
dual이 경우 미리 생성해야 합니까, 아니면 쿼리 만 사용하기 위해 쿼리에 의해 생성 된 특별한 "임시"테이블입니까?
itsmequinn 2012

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;
Jonathan Leffler

알아 두셔서 감사합니다
itsmequinn 2012

11
MySQL에서는 존재하기 위해 실제로 'dual'이라는 테이블을 가질 필요가 없습니다. 테이블에서 무엇이든 선택하는 데 사용할 수있는 특별한 테이블 이름입니다.
Christopher Schultz 2013

3
MySQL은 "이중"개념을 "존중"하지만 실제로는 존재하지 않습니다. 예를 들어, 경우에 SELECT COUNT(*) FROM dual당신은 항상 얻을 1, 그리고 경우에 SELECT 'foo' FROM dual당신은 항상 얻을 foo. 하지만 당신은 할 수없고 SELECT * FROM dual할 수도 없습니다 DESCRIBE dual. 확인하지 않았지만에서 권한을 취소 할 수도 없다고 생각 dual합니다. 그것의 가치는 당신이 예상대로 작동하는지 지적 그래서 그렇지 않을 때 ...를 제외시켰다)
크리스토퍼 슐츠에게

52

INSERT IGNORE(사용자, 항목)에 고유 인덱스가있을 때 행을 업데이트하거나 삽입하는 대신 삽입을 자동으로 무시하는 것을 사용할 수도 있습니다 .

쿼리는 다음과 같습니다.

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 : 새 행을 유지합니다. 둘 다 고유 키에서 작동합니다.
Paul Kenjora

지금까지 가장 좋은 대답
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 문을 사용하여 좋은 솔루션
자바 ACM

좋은. 이것은 첫 번째 시도에서 postgresql에서 작동하며 수락 된 답변이 나에게 보이지 않는 것 같습니다.
mightypile 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)를 설정할 수 없습니다.
The Unknown

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

또는 실행 여부를 결정하기 위해 복잡한 논리를 사용하지 않기 때문에이 두 열의 조합에 키를 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

나는 당신이 from dual전에 말할 필요가 있다고 생각합니다 where.
hlin117

@ hlin117 MariaDB에서 FROM DUAL테이블이 참조되지 않은 경우 기본값이됩니다 ( 이 문서 참조 ).
Yeti

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

그래, 그래. 나는 그것을 잘못 읽었다. 쌍에 대한 제약을 만들기 위해 편집되었습니다.
NickZoic

좋은 의견 ... mysql_query ( "INSERT")를 사용하여 PHP에서 쿼리를 실행하고 또는 die Part를 남겨 두므로 오류에 대해 경고하지 않으므로 검사를 수행 할 필요가 없습니다
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.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.