Chèn có điều kiện MySQL


98

Tôi đang gặp khó khăn khi tạo CHÈN có điều kiện

Tôi có x_table với các cột (phiên bản, người dùng, mục) trong đó ID phiên bản là duy nhất. Tôi chỉ muốn chèn một hàng mới nếu người dùng chưa có một mục nhất định.

Ví dụ cố gắng chèn 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 

Bất kỳ sự giúp đỡ hoặc hướng dẫn đúng hướng sẽ được đánh giá cao.

Câu trả lời:


115

Nếu DBMS của bạn không đặt ra các giới hạn đối với bảng bạn chọn khi thực hiện chèn, hãy thử:

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)

Trong đây, duallà một bảng chỉ có một hàng (ban đầu được tìm thấy trong Oracle, bây giờ cũng trong mysql). Logic là câu lệnh SELECT tạo ra một hàng dữ liệu với các giá trị bắt buộc, nhưng chỉ khi các giá trị đó chưa được tìm thấy.

Ngoài ra, hãy xem báo cáo MERGE.


1
dualcần phải được tạo trước trong trường hợp này không hay đó là một loại bảng "tạm thời" đặc biệt nào đó được tạo bởi truy vấn để chỉ sử dụng truy vấn?
itmequinn

8
Nếu bạn chưa có dual, bạn cần tạo nó. 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

Cảm ơn điều đó thật tuyệt khi biết
itmequinn 24/02/12

11
Lưu ý rằng, trong MySQL, bạn không thực sự cần phải có một bảng được gọi là 'kép' để tồn tại: nó là một tên bảng đặc biệt có thể được sử dụng để chọn bất kỳ thứ gì từ nó.
Christopher Schultz

3
MySQL "tôn trọng" khái niệm "kép" nhưng nó không thực sự tồn tại. Ví dụ, nếu bạn SELECT COUNT(*) FROM dualluôn nhận được 1và nếu SELECT 'foo' FROM dualbạn luôn nhận được foo. Nhưng bạn không thể SELECT * FROM dualvà bạn không thể DESCRIBE dualhoặc bất cứ điều gì tương tự. Tôi chưa kiểm tra, nhưng tôi cũng không nghĩ rằng bạn có thể thu hồi quyền đối với dual. Vì vậy, đáng để chỉ ra rằng nó hoạt động như bạn mong đợi ... trừ khi nó không hoạt động;)
Christopher Schultz

52

Bạn cũng có thể sử dụng tính năng INSERT IGNOREnày bỏ qua phần chèn thay vì cập nhật hoặc chèn một hàng khi bạn bật chỉ mục duy nhất (người dùng, mục).

Truy vấn sẽ như thế này:

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

Bạn có thể thêm chỉ mục duy nhất với CREATE UNIQUE INDEX user_item ON x_table (user, item).


2
Theo tài liệu MySQL CHÈN BỎ QUA là bản đối chiếu để THAY THẾ ... CHÈN BỎ QUA: giữ các hàng cũ. THAY THẾ: giữ hàng mới. Cả hai đều hoạt động trên các phím duy nhất.
Paul Kenjora

Câu trả lời hay nhất từ ​​trước đến nay
jmojico 11/09/19

30

Bạn đã bao giờ thử một cái gì đó như vậy?

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;

ồ vâng! thông minh và giải pháp tốt đẹp chỉ với một câu lệnh SELECT
java acm

Đẹp. Điều này hoạt động cho postgresql trong lần thử đầu tiên, nơi mà câu trả lời được chấp nhận dường như không dành cho tôi.
strongpile

10

Với một UNIQUE(user, item), hãy làm:

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

các user=123bit là một "no-op" để phù hợp với cú pháp của ON DUPLICATEmệnh đề mà không thực sự làm bất cứ điều gì khi có bản sao.


1
Tôi không thể thiết lập Duy nhất (người dùng, mục) vì có thể có nhiều trường hợp với cùng một người dùng và mục ... nhưng không phải khi tôi thực hiện chèn này.
The Unknown

2

Trong trường hợp bạn không muốn đặt một ràng buộc duy nhất, điều này hoạt động giống như một sự quyến rũ:

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

Hy vọng nó giúp !


2

Những gì bạn muốn là INSERT INTO table (...) SELECT ... WHERE .... từ hướng dẫn sử dụng MySQL 5.6 .

Trong trường hợp của bạn, đó là:

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

Hoặc có thể vì bạn không sử dụng bất kỳ logic phức tạp nào để xác định có nên chạy INSERThay không, bạn có thể chỉ cần đặt một UNIQUEkhóa trên sự kết hợp của hai cột này và sau đó sử dụng INSERT IGNORE.


Bạn đã chạy câu trả lời của bạn? Tôi tiếp tục nhận được 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...(chạy 5.6.34)
hlin117

Tôi nghĩ bạn cần phải nói from dualtrước where.
hlin117

@ hlin117 Trong MariaDB FROM DUALlà mặc định nếu không có bảng nào được tham chiếu ( xem tài liệu này ).
Yeti

1

Nếu bạn thêm một ràng buộc (x_table.user, x_table.item) là duy nhất, thì việc chèn một hàng khác có cùng người dùng và mục sẽ không thành công.

ví dụ:

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

Điều đó không đúng. Có thể có nhiều hàng với cùng một người dùng, nhưng không có nhiều hàng có một cặp mục người dùng.
Matthew Flaschen

Tuyệt. Tôi đã đọc nhầm. Đã chỉnh sửa để tạo ràng buộc cho cặp.
NickZoic

Nhận xét tốt ... tôi chạy truy vấn trong PHP bằng cách sử dụng mysql_query ("INSERT") và để lại hoặc chết Phần do đó nó liều lượng cảnh báo cho tôi về lỗi nên tôi không phải thực hiện bất kỳ kiểm tra nào
Angel.King.47

1

Mặc dù rất tốt để kiểm tra sự trùng lặp trước khi chèn dữ liệu của bạn, tôi khuyên bạn nên đặt một ràng buộc / chỉ mục duy nhất trên các cột của mình để không có dữ liệu trùng lặp nào có thể bị chèn nhầm.


1

Bạn có thể sử dụng giải pháp sau để giải quyết vấn đề của mình:

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

Mặc dù mã này có thể trả lời câu hỏi, nhưng việc cung cấp thêm ngữ cảnh về cách và / hoặc lý do tại sao nó giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Nic3500,

0

Sửa đổi nhẹ đối với phản hồi của Alex, bạn cũng có thể chỉ tham khảo giá trị cột hiện có:

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

0

Vì vậy, cái này là viết tắt của 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);

Cú pháp có thể khác nhau tùy thuộc vào DB của bạn ...


2
Cái này dùng để làm gì? MySQL?
Umair A.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.