คำสั่ง“ แทรกหากไม่มีอยู่” ใน SQLite


143

ฉันมีฐานข้อมูล SQLite ฉันกำลังพยายามแทรกค่า ( users_id, lessoninfo_id) ในตารางbookmarksเฉพาะในกรณีที่ไม่มีทั้งสองอยู่ก่อนในแถว

INSERT INTO bookmarks(users_id,lessoninfo_id) 
VALUES(
    (SELECT _id FROM Users WHERE User='"+$('#user_lesson').html()+"'),
        (SELECT _id FROM lessoninfo 
        WHERE Lesson="+lesson_no+" AND cast(starttime AS int)="+Math.floor(result_set.rows.item(markerCount-1).starttime)+") 
        WHERE NOT EXISTS (
            SELECT users_id,lessoninfo_id from bookmarks 
            WHERE users_id=(SELECT _id FROM Users 
            WHERE User='"+$('#user_lesson').html()+"') AND lessoninfo_id=(
                SELECT _id FROM lessoninfo
                WHERE Lesson="+lesson_no+")))

นี่เป็นข้อผิดพลาดที่บอกว่า:

ข้อผิดพลาด db ใกล้กับที่ไวยากรณ์

คำตอบ:


138

หากคุณมีตารางที่เรียกว่าบันทึกช่วยจำที่มีสองคอลัมน์idและtextคุณควรทำดังนี้:

INSERT INTO memos(id,text) 
SELECT 5, 'text to insert' 
WHERE NOT EXISTS(SELECT 1 FROM memos WHERE id = 5 AND text = 'text to insert');

หากบันทึกมีแถวอยู่แล้วซึ่งtextมีค่าเท่ากับ 'text to insert' และidเท่ากับ 5 แล้วการดำเนินการแทรกจะถูกละเว้น

ฉันไม่ทราบว่าสิ่งนี้จะใช้ได้กับข้อความค้นหาเฉพาะของคุณหรือไม่ แต่อาจให้คำแนะนำเกี่ยวกับวิธีดำเนินการต่อ

ฉันอยากจะแนะนำให้คุณออกแบบตารางแทนเพื่อไม่อนุญาตให้มีรายการซ้ำตามที่อธิบาย@CLs answerด้านล่าง


436

หากคุณไม่ต้องการทำซ้ำคุณควรประกาศสิ่งนี้เป็นข้อ จำกัด ของตาราง:

CREATE TABLE bookmarks(
    users_id INTEGER,
    lessoninfo_id INTEGER,
    UNIQUE(users_id, lessoninfo_id)
);

(คีย์หลักเหนือทั้งสองคอลัมน์จะมีผลเหมือนกัน)

จากนั้นเป็นไปได้ที่จะบอกฐานข้อมูลว่าคุณต้องการเพิกเฉยต่อบันทึกที่จะละเมิดข้อ จำกัด ดังกล่าว :

INSERT OR IGNORE INTO bookmarks(users_id, lessoninfo_id) VALUES(123, 456)

12
อะไรคือวิธีที่ดีที่สุดในการรับ ID ของแถวที่เพิ่งแทรกใหม่หรือแถวที่มีอยู่แล้วดังนั้นฉันจึงสามารถแทรกเข้าไปในตารางอื่นที่มีรหัสต่างประเทศได้ เช่นฉันมีสองตารางperson (id, name unique)และcat (person_id, name unique)และฉันต้องการที่จะแทรกคู่มากมาย(person_name, cat_name)?
Aur Saraf

2
การอ่าน ID ของแถวที่มีอยู่เป็นไปได้เฉพาะกับแบบสอบถามแบบใช้เลือกข้อมูล แต่นี่เป็นคำถามที่แตกต่าง
CL

1
บางทีอาจจะเพิ่มON CONFLICT IGNOREไปCREATE TABLEจะเป็นบิตมากขึ้นมีประโยชน์
defhlt

1
@ rightaway717 "ละเว้น" หมายความว่าไม่มีอะไรเกิดขึ้น คำถามนี้ไม่เกี่ยวกับการอัพเดท
CL

1
@ Hack06 การแทรกของ Android () ทำงานแตกต่างกัน คุณควรจะแทนที่ด้วยinsertOrThrow ()หรือinsertWithOnConflict ()
CL

21

สำหรับคอลัมน์ที่ไม่ซ้ำให้ใช้สิ่งนี้:

INSERT OR REPLACE INTO table () values();

สำหรับข้อมูลเพิ่มเติมโปรดดูที่: sqlite.org/lang_insert


สิ่งนี้ไม่ได้ผลสำหรับฉัน มันแทรกเหมือนในการแทรกหรือแทนที่เป็นค่า my_table (col1, col2) ('1', '2'); จะเพิ่มหลายแถวของ 1 2
Peter Moore

ฉันอาจเพิ่มว่ามันทำงานได้ดีถ้ามีการวางข้อ จำกัดUnique(col1,col2)และคุณยังมี col3 ด้วยเนื่องจากการแทรกหรือเพิกเฉยจะล้มเหลวโดยที่สิ่งนี้จะอัปเดต col3 เป็นค่าใหม่ insert or replace into my_table values('1','2','5')แทนที่แถว'1','2','3'
Peter Moore

4
insert into bookmarks (users_id, lessoninfo_id)

select 1, 167
EXCEPT
select user_id, lessoninfo_id
from bookmarks
where user_id=1
and lessoninfo_id=167;

นี่เป็นวิธีที่เร็วที่สุด

สำหรับเอ็นจิน SQL อื่น ๆ คุณสามารถใช้ตาราง Dummy ที่มี 1 เรคคอร์ด เช่น:

select 1, 167 from ONE_RECORD_DUMMY_TABLE
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.