SQLite INSERT - TRÊN CẬP NHẬT KHÓA DUPLICATE (UPSERT)


98

MySQL có một cái gì đó như thế này:

INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON DUPLICATE KEY UPDATE hits = hits + 1;

Theo như tôi biết thì tính năng này không tồn tại trong SQLite, điều tôi muốn biết là có cách nào để đạt được hiệu ứng tương tự mà không cần phải thực hiện hai truy vấn hay không. Ngoài ra, nếu điều này là không thể, bạn muốn làm gì:

  1. CHỌN + (CHÈN hoặc CẬP NHẬT) hoặc
  2. CẬP NHẬT (+ CHÈN nếu CẬP NHẬT không thành công )

Câu trả lời:


31

Vì SQLite 3.24.0 cũng hỗ trợ nâng cấp , vì vậy bây giờ bạn có thể chỉ cần viết như sau

INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON CONFLICT(ip) DO UPDATE SET hits = hits + 1;

3
Tôi đã tự hỏi liệu bạn có thể thực hiện nhiều lần upsertnhư vậy trong một giao dịch, tức là với executemany()hàm Python không?
Đài kiểm soát

117
INSERT OR IGNORE INTO visits VALUES ($ip, 0);
UPDATE visits SET hits = hits + 1 WHERE ip LIKE $ip;

Điều này yêu cầu cột "ip" phải có ràng buộc DUY NHẤT (hoặc KHÓA CHÍNH).


CHỈNH SỬA: Một giải pháp tuyệt vời khác: https://stackoverflow.com/a/4330694/89771 .


2
Chỉ cho bản ghi, REPLACEkhông phải là một tùy chọn.
Alix Axel,

1
Về "khác lớn giải pháp" liên kết, tôi cũng sẽ xem xét một câu trả lời khác nhau cho cùng một câu hỏi: stackoverflow.com/a/418988/3650835
KayakinKoder

19

Tôi thích hơn UPDATE (+ INSERT if UPDATE fails). Ít mã hơn = ít lỗi hơn.


1
Cảm ơn! @Sam ( stackoverflow.com/questions/418898/… ) có vẻ đồng ý với bạn. Tôi cũng thích cách tiếp cận này hơn.
Alix Axel

@Smith Ý tôi là sử dụng câu lệnh UPDATE và INSERT đơn giản và kiểm tra giá trị trả về.
codeholic

Điều này không có tính nguyên tử, có thể INSERT sẽ thất bại nếu một số quá trình khác được chèn vào giữa.
Robin Lavallée

7

Câu trả lời hiện tại sẽ chỉ hoạt động trong sqlite HOẶC mysql (tùy thuộc vào việc bạn có sử dụng HOẶC hay không). Vì vậy, nếu bạn muốn khả năng tương thích chéo dbms, những điều sau sẽ làm ...

REPLACE INTO `visits` (ip, value) VALUES ($ip, 0);

3
Câu trả lời được chấp nhận hoạt động trên SQLite (đó là mục đích của tôi). REPLACEcũng sẽ hoạt động trên SQLite, nhưng trên MySQL, nó sẽ luôn đặt lại bộ đếm về 0 - trong khi truy vấn sẽ di động, kết quả cuối cùng sẽ khác rất nhiều.
Alix Axel,

Bạn nói đúng, tôi nghĩ OP đang tìm kiếm thứ gì đó có thể di chuyển được. Tôi nhận ra rằng REPLACE INTO sẽ không hoạt động với mọi trường hợp, đặc biệt là những trường hợp cần bảo toàn PK, nhưng sẽ áp dụng cho nhiều trường hợp.
Jacob Thomason

Không xóa sạch thay vì loại bỏ dữ liệu là một tính năng, không phải lỗi.
Tobu

-4

Bạn nên sử dụng memcached cho việc này vì nó là một khóa duy nhất (địa chỉ IP) lưu trữ một giá trị duy nhất (số lượt truy cập). Bạn có thể sử dụng hàm tăng nguyên tử để đảm bảo không có điều kiện "chủng tộc".

Nó nhanh hơn MySQL và tiết kiệm tải để MySQL có thể tập trung vào những thứ khác.


Nếu dữ liệu không quan trọng, thì có. Tuy nhiên, nếu điều này đang được sử dụng trên một trang web bận rộn có nhiều IP đang sử dụng dịch vụ, (các) phiên bản memcached có thể bị đầy và khiến một số nội dung bị xóa. Sao lưu nội dung memcached sẽ cũng rất thú vị (nếu có yêu cầu.)
Elliot Foster

@ElliotFoster Memcached có thể xử lý nhiều dữ liệu tương đương với RAM mà bạn ném vào nó (nếu bạn muốn cá tính thì hãy sử dụng redis hoặc membase). Nếu bạn nhận được hơn 1 triệu khách truy cập mỗi ngày thì bạn có thể đủ khả năng cung cấp cho phiên bản memcache của mình hơn 30MB ram (tôi nghĩ là mặc định). Tuy nhiên, nó chắc chắn có thể xử lý tải cao hơn nhiều so với SQLite và MySQL đối với dung lượng bộ nhớ mà bạn cung cấp - không có bất kỳ sự so sánh nào.
Xeoncross

Xin đừng nhầm nhận xét của tôi là một cuộc bỏ phiếu chống lại memcache, vì tôi nghĩ nó là một công cụ tuyệt vời. Redis cũng vậy (tôi không thể nói về membase, vì tôi chưa sử dụng nó.) Tuy nhiên, memcache / redis không phải là cửa hàng đáng tin cậy nhất. Có, redis có tính bền bỉ, nhưng dữ liệu được lưu vào đĩa trong một khoảng thời gian (lần cuối tôi xem) và memcache thì không. Như tôi đã nói, nếu dữ liệu không quan trọng (hoặc có thể được sao chép dễ dàng) thì memcache và công ty là tuyệt vời. Bài đăng ban đầu cũng hỏi về sqlite, rất khác với MySQL và có thể có nghĩa là chúng bị hạn chế theo những cách khác.
Elliot Foster

Bạn có thể định cấu hình Redis để duy trì dữ liệu nhanh như bạn muốn (ở X số giây hoặc Y số lần thay đổi).
Buffalo
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.