2013-03-06 43 views
5

Tôi đang tìm một câu lệnh SQL chuẩn "UPSERT". Một cuộc gọi để chèn và cập nhật nếu tồn tại.UPSERT tiêu chuẩn SQL gọi

Tôi đang tìm kiếm một cuộc gọi hiệu quả, hiệu quả và đa nền tảng.

Tôi đã xem MERGE, UPSERT, REPLACE, INSERT .. ON DUPLICATE UPDATE nhưng không tuyên bố nào đáp ứng được nhu cầu.

BTW Tôi sử dụng MYSQL và HSQLDB cho các đơn vị. Tôi hiểu rằng HSQLDB bị hạn chế và có thể không bao gồm những gì tôi cần, nhưng tôi không thể tìm thấy một cách tiêu chuẩn ngay cả khi không có nó. Một tuyên bố rằng chỉ MYSQL và HSQLDB cũng sẽ là đủ cho bây giờ.

Tôi đã xem xét một lúc và không thể nhận được câu trả lời.

bảng của tôi:

CREATE TABLE MY_TABLE (
    MY_KEY varchar(50) NOT NULL , 
    MY_VALUE varchar(50) DEFAULT NULL, 
    TIME_STAMP bigint NOT NULL, 
    PRIMARY KEY (MY_KEY) 
); 

Bất kỳ ý tưởng?

Thanx;)

+0

'INSERT .. ON DUPLICATE UPDATE' là chìa khóa trong 'mYSQL'. bạn có thể hiển thị một số bản ghi hoặc có thể cấu trúc bảng? –

+0

Đúng nhưng chỉ được hỗ trợ trong MYSQL. HSQLDB và tất cả những người khác không sử dụng nó ... – BobTheBuilder

+0

có một hợp nhất ANSI (http://en.wikipedia.org/wiki/Merge_%28SQL%29), nhưng nó không được thực hiện trong tất cả các DBMS. Vì vậy, không có hy vọng cho một lệnh phổ quát. –

Trả lời

4

Giải pháp duy nhất được hỗ trợ bởi cả MySQL và HSQLDB là truy vấn các hàng bạn dự định thay thế và có điều kiện INSERT hoặc UPDATE. Điều này có nghĩa là bạn phải viết thêm mã ứng dụng để bù đắp cho sự khác biệt giữa việc triển khai RDBMS.

  1. BẮT ĐẦU GIAO DỊCH.
  2. CHỌN ... ĐỂ CẬP NHẬT.
  3. Nếu SELECT tìm thấy hàng, sau đó UPDATE.
  4. Khác, INSERT.
  5. COMMIT.

MySQL không hỗ trợ câu lệnh ANSI SQL MERGE. Nó hỗ trợ REPLACE và INSERT ... ON UPDATE DUPLICATE KEY. Xem câu trả lời của tôi cho "INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE" để biết thêm về điều đó.


Trả lời: Có, cách tiếp cận khác là chỉ cần thử INSERT và xem liệu nó có thành công hay không. Nếu không, hãy cập nhật. Nếu bạn cố gắng INSERT và nó nhấn một khóa trùng lặp, nó sẽ tạo ra một lỗi, biến thành một ngoại lệ trong một số giao diện máy khách. Những bất lợi của việc này trong MySQL là nó tạo ra một ID tự động tăng mới ngay cả khi INSERT không thành công. Vì vậy, bạn kết thúc với những khoảng trống. Tôi biết khoảng trống trong chuỗi tự động tăng thường không phải là điều đáng lo ngại, nhưng tôi đã giúp khách hàng năm ngoái có khoảng trống 1000-1500 giữa các lần chèn thành công vì hiệu ứng này và kết quả là họ đã cạn kiệt phạm vi INT trong khóa chính của họ.

Như @baraky nói, thay vào đó, người dùng có thể thử UPDATE trước và nếu điều đó ảnh hưởng đến hàng không, thì hãy thực hiện INSERT thay thế. Nhận xét của tôi về chiến lược này là UPDATEing zero rows không phải là một ngoại lệ - bạn sẽ phải kiểm tra "số hàng bị ảnh hưởng" sau khi UPDATE để biết liệu nó có "thành công" hay không.

Nhưng việc truy vấn số hàng bị ảnh hưởng sẽ trả về bạn cho vấn đề ban đầu: bạn phải sử dụng các truy vấn khác nhau trong MySQL so với HSQLDB.

HSQLDB:

CALL DIAGNOSTICS(ROW_COUNT); 

MySQL:

SELECT ROW_COUNT(); 
+0

Hoặc thực hiện INSERT, bắt SQLException và nếu nó là một vi phạm ràng buộc toàn vẹn, thực hiện một UPDATE – fredt

+0

Thực sự đó là (gần như) những gì tôi sẽ làm - Tôi sẽ cập nhật, bắt ngoại lệ (như cập nhật là trường hợp phổ biến cho tôi) và chèn nếu không thành công. Thanx! – BobTheBuilder

3

Cú pháp để thực hiện lệnh upsert trong một lệnh khác nhau tùy theo RDBMS.

Trong MySQL nó INSERT...ON DUPLICATE KEY UPDATE

Trong HSQLDB nó MERGE

Nếu bạn muốn có một giải pháp đa nền tảng, sau đó bạn sẽ cần phải sử dụng nhiều lệnh. Trước tiên hãy kiểm tra hàng hiện tại, sau đó điều kiện chèn hoặc cập nhật khi thích hợp.

+0

Tôi không muốn sử dụng nhiều lệnh.Không có ý tưởng nào khác về cách thử nghiệm và dev sẽ chạy cùng một mã? – BobTheBuilder

+0

Tôi vẫn khuyên bạn nên làm điều đó bằng mã có điều kiện. Nếu bạn không làm điều đó, hãy xem xét chuẩn hóa thử nghiệm của bạn và dev môi trường để sử dụng cùng một RD BMS. –

+0

@baraky: nếu bạn muốn hỗ trợ nhiều DBMS, bạn sẽ không bao giờ có thể giải quyết mọi vấn đề với một câu lệnh chạy trên tất cả DBMS. Hãy sẵn sàng để có tuyên bố cụ thể DBMS. Mọi thứ khác sẽ thất bại. –