2010-04-18 69 views
7

Mặc dù tôi đang sử dụng mySQL (bây giờ), tôi không muốn bất kỳ SQL cụ thể DB nào.Câu hỏi SQL ANSI - cách chèn hoặc cập nhật bản ghi nếu nó đã tồn tại?

Tôi đang cố gắng chèn một bản ghi nếu nó không tồn tại và cập nhật một trường nếu nó tồn tại. Tôi muốn sử dụng ANSI SQL.

Bảng trông giống như sau:

create table test_table (id int, name varchar(16), weight double) ; 

//test data 
insert into test_table (id, name, weight) values(1,'homer', 900); 
insert into test_table (id, name, weight) values(2,'marge', 85); 
insert into test_table (id, name, weight) values(3,'bart', 25); 
insert into test_table (id, name, weight) values(4,'lisa', 15); 

If the record exists, I want to update the weight (increase by say 10) 

Trả lời

7

Trong một thời gian dài hoạt động này đòi hỏi hai lệnh riêng biệt cộng với một số khuôn khổ để xử lý nó. Do đó tên UPSERT (UPdate hoặc inSERT). Nhưng các phiên bản gần đây của một số hương vị của DBMS hỗ trợ các giải pháp thanh lịch hơn.

Tiêu chuẩn ANSI xác định a MERGE syntax. Điều này đã được hỗ trợ trong Oracle kể từ phiên bản 9i và trong MS SQL Server từ năm 2005. Các báo cáo MERGE có thể hơi tiết.

merge into t23 
using t42 
on t42.id = t23.id 
when matched then 
    update 
    set  t23.col1 = t42.col1 
when not matched then 
    insert (id, col1) 
    values (t42.id, t42.col1) 
/

Tôi nghĩ rằng lệnh MERGE chủ yếu được dự kiến ​​như là một công cụ chuyển đổi dữ liệu, vì vậy nhu cầu cú pháp của nó mà chúng ta chọn dữ liệu từ một bảng, trong mệnh đề SỬ DỤNG. chúng ta có thể vượt qua giới hạn này bằng cách chọn các literals và pseudo-columns từ một thiết bị tạo hàng (chẳng hạn như dual trong Oracle).

MySQL có một cú pháp khác biệt rõ ràng, INSERT ... ON DUPLICATE KEY UPDATE.

+0

Tôi đã kết thúc bằng cách sử dụng INSERT .. ON UPDATE DUPLICATE KEY – morpheous

+4

MS SQL Server 2005 không hỗ trợ cú pháp MERGE. Chỉ SQL Server 2008 trở lên mới hỗ trợ nó. –

+1

Có vẻ như máy chủ sql 2005 beta đã có nó nhưng không phải là bản phát hành cuối cùng. Năm 2008 đã nhận được nó. Tham khảo: http://geekswithblogs.net/SabotsShell/archive/2005/08/20/50706.aspx – Alex

1

này được định nghĩa trong SQL3 như MERGE.

+0

vĩ đại giải pháp, quá xấu mà rất nhiều cơ sở dữ liệu không hỗ trợ này SQL Server chưa :( – Wolph

+0

2005 hỗ trợ MERGE, cũng như Oracle 9i (và cao hơn) – APC

+0

SQL 2005 không hỗ trợ hợp nhất, nó đã được giới thiệu trong SQL 2008 –

1

Sử dụng một cặp UPSERT các lệnh:

update test_table inner join test_table lookup 
on test_table.id = lookup.id 
and lookup.name = 'bart' 
set test_table.colA = .... 

insert into test_table 
select 1,'xxx', 999 
from dual where exists <...> 
+0

Đó sẽ là Oracle cụ thể, phải không? – Wolph

+1

no: bạn cũng có thể sử dụng bảng kép trong mySql. Và trong SQL Server, bạn có thể bỏ qua hoàn toàn nếu tất cả những gì bạn cần là SELECT . – davek

0

Một cách để làm điều này chỉ đơn giản là thực hiện một chèn và cập nhật lệnh, bỏ qua những lỗi vào ngày đầu tiên nếu có đã bản ghi có khóa đó:

try: 
    insert into test_table (id, name, weight) values(1,'pax',0) 
catch (e): 
    pass 
update test_table set weight = weight * 1.1 where id = 1 

Nếu bạn muốn trọng lượng của một mục tạo ra được (ví dụ) 72 tuổi, sử dụng như là báo cáo kết quả đầu tiên:

insert into test_table (id, name, weight) values(1,'pax',72/1.1) 
2

Một cách tiếp cận phù hợp với tiêu chuẩn SQL cũ và do đó tương thích với một phạm vi rộng của DBMS (như của bây giờ SQLite, ví dụ, does not support MERGE) là sử dụng a technique involving a mutex table:

CREATE TABLE mutex (i INT); 
INSERT INTO mutex VALUES (0); 

Đó phép thi đua của một INSERT NẾU KHÔNG EXISTS tuyên bố:

INSERT INTO test_table (id, name, weight) 
    SELECT 1, 'homer', 900 
    FROM mutex LEFT JOIN test_table 
    ON id = 1 
    WHERE i = 0 AND id IS NULL; 

trong trường hợp của câu hỏi của OP đó sẽ là sau bởi một UPDATE đơn giản:

UPDATE test_table SET weight = weight + 10 WHERE id = 1; 
+0

Thực sự tôi đăng bài này để tham khảo của riêng tôi bởi vì nguồn tôi có (xaprb.com) không dễ dàng đến trên các tìm kiếm của Google. :) –

+2

Tôi thích giải pháp của bạn, bởi vì nó sẽ hoạt động trên hầu như bất kỳ DBMS nào. Nhưng tôi thấy một chút cải thiện. Bạn thực sự không cần bảng mutex. Chỉ cần làm một subselect để 'FROM mutex LEFT JOIN test_table' trở thành' FROM (SELECT 0 AS i) AS mutex LEFT JOIN test_table' – JHoffmann

Các vấn đề liên quan