SQLite INSERT - ในการอัปเดตคีย์ซ้ำ (UPSERT)


98

MySQL มีดังนี้:

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

เท่าที่ฉันรู้ว่าคุณสมบัตินี้ไม่มีอยู่ใน SQLite สิ่งที่ฉันอยากรู้คือมีวิธีใดบ้างที่จะได้เอฟเฟกต์เดียวกันโดยไม่ต้องดำเนินการสองแบบสอบถาม นอกจากนี้หากไม่สามารถทำได้คุณต้องการอะไร:

  1. SELECT + (INSERT หรือ UPDATE)หรือ
  2. UPDATE (+ INSERT หาก UPDATE ล้มเหลว )

คำตอบ:


34

ตั้งแต่ 3.24.0 SQLite ยังรองรับ upsertดังนั้นตอนนี้คุณสามารถเขียนสิ่งต่อไปนี้ได้

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

3
ฉันสงสัยว่าคุณสามารถทำหลาย ๆupsertอย่างในธุรกรรมเดียวได้หรือไม่เช่นด้วยexecutemany()ฟังก์ชันPython ?
วิทยุควบคุม

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

สิ่งนี้ต้องการให้คอลัมน์ "ip" มีข้อ จำกัด UNIQUE (หรือ PRIMARY KEY)


แก้ไข: อีกวิธีที่ดี: https://stackoverflow.com/a/4330694/89771


2
สำหรับบันทึกREPLACEไม่ใช่ตัวเลือก
Alix Axel

1
เกี่ยวกับลิงก์ "วิธีแก้ปัญหาที่ยอดเยี่ยมอื่น ๆ " ฉันจะพิจารณาคำตอบอื่นสำหรับคำถามเดียวกัน: stackoverflow.com/a/418988/3650835
KayakinKoder

19

UPDATE (+ INSERT if UPDATE fails)ฉันไม่ต้องการ รหัสน้อย = จุดบกพร่องน้อยลง


1
ขอบคุณ! @Sam ( stackoverflow.com/questions/418898/… ) ดูเหมือนจะเห็นด้วยกับคุณ ฉันชอบแนวทางนี้ด้วย
Alix Axel

@Smith ฉันหมายถึงการใช้คำสั่ง UPDATE และ INSERT ธรรมดาและตรวจสอบค่าส่งคืน
codeholic

สิ่งนี้ไม่มีความเป็นอะตอมเป็นไปได้ที่ INSERT จะล้มเหลวหากมีกระบวนการอื่นแทรกอยู่ระหว่าง
Robin Lavallée

7

คำตอบปัจจุบันจะใช้ได้เฉพาะใน sqlite หรือ mysql เท่านั้น (ขึ้นอยู่กับว่าคุณใช้หรือไม่) ดังนั้นหากคุณต้องการความเข้ากันได้ข้าม dbms สิ่งต่อไปนี้จะทำ ...

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

3
คำตอบที่ยอมรับทำงานบน SQLite (นั่นคือเป้าหมายของฉัน) REPLACEจะทำงานบน SQLite ด้วยเช่นกัน แต่บน MySQL จะรีเซ็ตตัวนับเป็น 0 เสมอ - ในขณะที่แบบสอบถามจะพกพาได้ผลลัพธ์สุดท้ายจะแตกต่างกันมาก
Alix Axel

คุณพูดถูกฉันคิดว่า OP กำลังมองหาสิ่งที่พกพาได้ ฉันตระหนักดีว่า REPLACE INTO ใช้ไม่ได้กับทุกกรณีโดยเฉพาะในกรณีที่จำเป็นต้องมีการเก็บรักษา PK แต่จะใช้กับหลาย ๆ กรณี
Jacob Thomason

การล้มเหลวอย่างหมดจดแทนที่จะทิ้งข้อมูลเป็นคุณลักษณะไม่ใช่ข้อบกพร่อง
Tobu

-4

คุณควรใช้ memcached สำหรับสิ่งนี้เนื่องจากเป็นคีย์เดียว (ที่อยู่ IP) เก็บค่าเดียว (จำนวนการเยี่ยมชม) คุณสามารถใช้ฟังก์ชันการเพิ่มอะตอมเพื่อประกันว่าไม่มีเงื่อนไข "การแข่งขัน"

เร็วกว่า MySQL และประหยัดการโหลดเพื่อให้ MySQL สามารถมุ่งเน้นไปที่สิ่งอื่น ๆ


ถ้าข้อมูลไม่สำคัญก็ใช่ อย่างไรก็ตามหากมีการใช้สิ่งนี้ในไซต์ที่มีคนพลุกพล่านซึ่งมี IP จำนวนมากกำลังกดเข้าใช้บริการอินสแตนซ์ memcached อาจเต็มและทำให้เนื้อหาบางส่วนตกหล่น การสำรองเนื้อหา memcached ก็น่าสนใจเช่นกัน (ถ้าจำเป็น)
Elliot Foster

@ElliotFoster Memcached สามารถจัดการข้อมูลได้มากเท่ากับ RAM ที่คุณโยนทิ้งไป (ถ้าคุณต้องการความคงอยู่ให้ใช้ redis หรือ membrane) หากคุณมีผู้เยี่ยมชมมากกว่า 1 ล้านคนในแต่ละวันคุณอาจจ่ายให้อินสแตนซ์ memcache ของคุณมากกว่า 30MB ของ ram (ซึ่งเป็นค่าเริ่มต้นที่ฉันคิด) อย่างไรก็ตามสามารถรองรับการโหลดที่สูงกว่า SQLite และ MySQL สำหรับจำนวนหน่วยความจำที่คุณให้ - ไม่มีการเปรียบเทียบใด ๆ
Xeoncross

โปรดอย่าเข้าใจผิดว่าความคิดเห็นของฉันเป็นการโหวตกับ memcache เพราะฉันคิดว่ามันเป็นเครื่องมือที่ยอดเยี่ยม เช่นเดียวกับ redis (ฉันไม่สามารถพูดถึงเมมเบสได้เนื่องจากฉันไม่ได้ใช้มัน) อย่างไรก็ตาม memcache / redis ไม่ใช่ร้านที่น่าเชื่อถือที่สุด ใช่ redis มีความคงอยู่ แต่ข้อมูลยังคงอยู่ในดิสก์ในช่วงเวลาหนึ่ง (สุดท้ายที่ฉันดู) และ memcache ไม่มีเลย อย่างที่ฉันบอกถ้าข้อมูลไม่สำคัญ (หรือสามารถทำซ้ำได้ง่าย) memcache และ บริษัท ก็ยอดเยี่ยม โพสต์ต้นฉบับยังถามเกี่ยวกับ sqlite ซึ่งแตกต่างจาก MySQL มากและน่าจะหมายความว่าพวกเขาถูก จำกัด ด้วยวิธีอื่น
Elliot Foster

คุณสามารถกำหนดค่า Redis ให้คงข้อมูลได้เร็วเท่าที่คุณต้องการ (ที่ X จำนวนวินาทีหรือที่จำนวนการเปลี่ยนแปลง Y)
ควาย
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.