PostgreSQL INSERT TRÊN CẬP NHẬT CONFLICT (upsert) sử dụng tất cả các giá trị bị loại trừ


142

Khi bạn đang nâng cấp một hàng (PostgreSQL> = 9.5) và bạn muốn INSERT có thể giống hệt như CẬP NHẬT có thể, bạn có thể viết nó như sau:

INSERT INTO tablename (id, username, password, level, email) 
                VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') 
ON CONFLICT (id) DO UPDATE SET 
  id=EXCLUDED.id, username=EXCLUDED.username,
  password=EXCLUDED.password, level=EXCLUDED.level,email=EXCLUDED.email

Có cách nào ngắn hơn không? Để chỉ nói: sử dụng tất cả các giá trị EXCLUDE.

Trong SQLite tôi thường làm:

INSERT OR REPLACE INTO tablename (id, user, password, level, email) 
                        VALUES (1, 'John', 'qwerty', 5, 'john@mail.com')

43
Không phải là một câu trả lời thật nhưng bạn có thể sử dụng một chút thời gian ngắn ký hiệu: INSERT INTO tablename (id, username, password, level, email) VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') ON CONFLICT (id) DO UPDATE SET (username, password, level, email) = (EXCLUDED.username, EXCLUDED.password, EXCLUDED.level, EXCLUDED.email).Hầu như giống nhau, nhưng dễ dàng để sao chép / dán / quản lý danh sách cột
chú ngựa

Một tùy chọn khác là sử dụng các cột jsonb và theo cách đó bạn không phải lo lắng về các cột
j sẽ vào

Câu trả lời:


162

Postgres đã không thực hiện tương đương với INSERT OR REPLACE. Từ các ON CONFLICTtài liệu (nhấn mạnh của tôi):

Nó có thể là KHÔNG NÊN, hoặc một mệnh đề DO UPDATE chỉ định chi tiết chính xác của hành động CẬP NHẬT sẽ được thực hiện trong trường hợp có xung đột.

Mặc dù nó không cung cấp cho bạn tốc ký thay thế, nhưng ON CONFLICT DO UPDATEáp dụng chung hơn, vì nó cho phép bạn đặt các giá trị mới dựa trên dữ liệu có sẵn. Ví dụ:

INSERT INTO users (id, level)
VALUES (1, 0)
ON CONFLICT (id) DO UPDATE
SET level = users.level + 1;

3
Như một lời cảnh báo, "cập nhật" không giống nhau về mặt ngữ nghĩa với "hợp nhất" của tiêu chuẩn SQL, mặc dù nó thường có thể được sử dụng ở cùng một nơi. Tôi đã có một trường hợp mà tôi mong đợi "cập nhật xung đột" sẽ xảy ra, nhưng vấn đề chính xác trong phần chèn không khiến bản cập nhật (sẽ sửa chữa bản ghi bị hỏng) phát sinh.
pojo-guys

2
Bạn có thể mở rộng "nhưng vấn đề chính xác trong phần chèn không gây ra cập nhật" không?
MrR

@ pojo-guys - Tôi không nghĩ rằng bạn đã thấy câu hỏi từ MrR - Bạn có thể mở rộng về "nhưng vấn đề chính xác trong phần chèn không gây ra cập nhật" không?
Randall

Khi bạn cố gắng sử dụng insert ... khi cập nhật trong postgresql, kết quả sẽ khác trong một số trường hợp cụ thể so với hợp nhất. Trường hợp tôi gặp phải khá mơ hồ và cụ thể, nhưng nó có thể lặp lại. Đã được một vài tháng, vì vậy tôi không thể cung cấp thêm nữa.
pojo-chàng

Có lẽ đó không phải là xung đột nhưng một lỗi khác, ví dụ như lỗi loại trường?
MrR
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.