จะเลือกระเบียนทั้งหมดจากตารางหนึ่งที่ไม่มีอยู่ในตารางอื่นได้อย่างไร


คำตอบ:


843
SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL

ถาม : เกิดอะไรขึ้นที่นี่

ตอบ : ตามหลักการแล้วเราเลือกแถวทั้งหมดจากtable1และสำหรับแต่ละแถวที่เราพยายามค้นหาแถวtable2ด้วยค่าเดียวกันสำหรับnameคอลัมน์ หากไม่มีแถวดังกล่าวเราเพียงปล่อยtable2ส่วนของผลลัพธ์ว่างไว้สำหรับแถวนั้น จากนั้นเรา จำกัด การเลือกของเราโดยเลือกเฉพาะแถวเหล่านั้นในผลลัพธ์ที่ไม่มีแถวที่ตรงกัน สุดท้ายเราไม่สนใจฟิลด์ทั้งหมดจากผลลัพธ์ของเรายกเว้นnameคอลัมน์ (อันที่เรามั่นใจว่ามีอยู่table1)

แม้ว่ามันอาจจะไม่ใช่วิธีที่มีประสิทธิภาพมากที่สุดเท่าที่จะเป็นไปได้ในทุกกรณี แต่ก็ควรใช้งานได้กับทุกเอนจิ้นฐานข้อมูลที่เคยใช้ANSI 92 SQL


16
@ z-boss: มันยังมีประสิทธิภาพน้อยที่สุดบน SQL Server: explextended.com/2009/09/15/…
OMG Ponies

7
@BunkerBoy: การเข้าร่วมด้านซ้ายช่วยให้แถวด้านขวาไม่มีอยู่หากไม่ส่งผลต่อการรวมแถวทางด้านซ้าย การรวมภายในจะต้องมีแถวด้านซ้ายและด้านขวา สิ่งที่ฉันทำที่นี่คือการใช้ตรรกะบางอย่างโดยทั่วไปจะได้รับการเลือกกลับเข้าร่วมภายใน
กริช

2
omg สิ่งนี้ช่วยให้มองเห็นภาพได้ง่ายมาก ๆ คนอื่น ๆ คิดว่ามันมี 5 วิธีที่แตกต่างกัน แต่มันก็ช่วยได้ ง่าย ๆ : ก่อนอื่นคุณต้องละทิ้งการเข้าร่วมทุกอย่างใน A และทุกอย่างใน B ที่ตรงกับ A แต่เมื่อเกิดขึ้นในการเข้าร่วมด้านซ้ายที่ไม่ได้เข้าร่วมก็เป็นเพียงโมฆะ จากนั้นคุณบอกว่าโอเคฉันแค่ต้องการที่จะเป็นโมฆะ ด้วยวิธีนี้คุณจะมีแถวทั้งหมดใน A ที่ไม่มีคู่ที่ตรงกันใน B
Muhammad Umer

7
ควรสังเกตว่าโซลูชันนี้ (ยอมรับและโหวต) เป็นโซลูชั่นเดียวที่ฉันสามารถแก้ไขได้สำหรับสถานการณ์ที่มีฟิลด์มากกว่าหนึ่งฟิลด์เข้ามาเล่น โดยเฉพาะฉันกำลังกลับฟิลด์ 2 และ 3 จากตารางที่ 1 ซึ่งการรวมกันของ field ad field2 ไม่ได้อยู่ในตารางที่สอง นอกเหนือจากการแก้ไขการเข้าร่วมในคำตอบนี้ฉันไม่เห็นวิธีที่จะทำกับบางส่วนของ "คำตอบที่มีประสิทธิภาพมากขึ้น" อื่น ๆ แย้งด้านล่าง
TMWP

1
เพียงตรวจสอบให้แน่ใจว่าคุณใช้ "WHERE t2.name IS NULL" และไม่ใช่ "และ t2.name IS NULL" เพราะ "และ" จะไม่ให้ผลลัพธ์ที่ถูกต้อง ฉันไม่เข้าใจว่าทำไม แต่จริง ๆ แล้วฉันทดสอบมัน
user890332

236

คุณสามารถทำได้

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

หรือ

SELECT name 
FROM table2 
WHERE NOT EXISTS 
    (SELECT * 
     FROM table1 
     WHERE table1.name = table2.name)

ดูคำถามนี้สำหรับ 3 เทคนิคเพื่อทำสิ่งนี้


38
สิ่งนี้ช้าอย่างไม่น่าเชื่อกับข้อมูลจำนวนมาก
Lightbulb1

ใช่แน่นอนมันช้ามาก
sirus

ไม่ควรเป็น "from table1" ในแบบสอบถามย่อยของแบบสอบถามที่ไม่มีอยู่
Hound

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

อันนี้ใช้ได้สำหรับฉัน .. ขอบคุณ
Thameem

81

ฉันไม่มีคะแนนตัวแทนมากพอที่จะโหวตคำตอบที่ 2 แต่ฉันต้องไม่เห็นด้วยกับความคิดเห็นในคำตอบที่ดีที่สุด คำตอบที่สอง:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

FAR มีประสิทธิภาพมากขึ้นในทางปฏิบัติ ฉันไม่รู้ว่าทำไม แต่ฉันใช้กับบันทึก 800k + และความแตกต่างเป็นอย่างมากกับประโยชน์ที่ได้จากคำตอบที่ 2 ที่โพสต์ข้างต้น แค่ $ 0.02 ของฉัน


30
ในแบบสอบถามแบบไม่ IN แบบสอบถามย่อยจะดำเนินการเพียงครั้งเดียวในแบบสอบถาม EXISTS แบบสอบถามย่อยจะดำเนินการสำหรับทุกแถว
Carrick

1
คุณยอดเยี่ยม :) ด้วยวิธีนี้ฉันแปลงการค้นหา 25 วินาทีโดยใช้การเข้าร่วมซ้ายเพียง 0.1 วินาที
Bassem Shahin

3
คำตอบไม่ได้อยู่ในลำดับที่เฉพาะเจาะจงดังนั้นคำตอบที่สองไม่ได้หมายความว่าคุณคิดว่ามันหมายถึงอะไร

38

นี่คือทฤษฎีเซตบริสุทธิ์ที่คุณสามารถทำได้ด้วยการminusดำเนินการ

select id, name from table1
minus
select id, name from table2

คุณคิดว่านี่มีประสิทธิภาพมากกว่าการเข้าร่วมที่เหลืออยู่หรือไม่?
uhs

มันควรจะเป็น. คำสั่งลบถูกออกแบบมาสำหรับสถานการณ์ที่แน่นอนนี้ แน่นอนวิธีเดียวที่จะตัดสินชุดข้อมูลใด ๆ โดยเฉพาะคือลองทั้งสองวิธีและดูว่าชุดไหนทำงานได้เร็วกว่า
ฤดูหนาว

9
ใน T-SQL ตัวดำเนินการตั้งค่าคือ "ยกเว้น" นี่สะดวกมากสำหรับฉันและไม่ได้ทำให้เกิดการชะลอตัวใด ๆ

2
ใน SQLite ตัวดำเนินการ "ลบ" ก็เป็น "ยกเว้น" เช่นกัน
lifjoy

MySQL ไม่รองรับผู้ให้บริการลบ
มูฮัมหมัดอาเซม


16

ระวังข้อผิดพลาด หากฟิลด์NameในTable1Null มีคุณอยู่ในความประหลาดใจ ดีกว่าคือ:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT ISNULL(name ,'')
     FROM table1)

1
เชื่อมต่อกัน> ISNULL (ISNULL เป็น T-SQL นอกจากไม่มีประโยชน์ที่จะภาษาที่ไม่ได้ทำอะไรใหม่หรือเชื่อมต่อกันดีกว่า)
คริส

14

นี่คือสิ่งที่ดีที่สุดสำหรับฉัน

SELECT *
FROM @T1
EXCEPT
SELECT a.*
FROM @T1 a
JOIN @T2 b ON a.ID = b.ID

นี่เร็วกว่าสองเท่าเหมือนกับวิธีอื่นที่ฉันลอง


ขอบคุณสิ่งนี้ใช้ได้ดีกับข้อมูลจำนวนมากเช่นกัน! แต่ฉันแค่สงสัยเกี่ยวกับคำว่า 'ยกเว้น'
PatsonLeaner


7

นั่นทำงานได้ดีสำหรับฉัน

SELECT * 
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL

1

ดูข้อความค้นหา:

SELECT * FROM Table1 WHERE
id NOT IN (SELECT 
        e.id
    FROM
        Table1 e
            INNER JOIN
        Table2 s ON e.id = s.id);

แนวคิดจะเป็น: การดึงระเบียนที่ตรงกันในแบบสอบถามย่อยแล้วในแบบสอบถามหลักดึงข้อมูลระเบียนที่ไม่ได้อยู่ในแบบสอบถามย่อย


0

ฉันจะโพสต์ใหม่ (เนื่องจากฉันยังไม่เจ๋งพอที่จะแสดงความคิดเห็น) ในคำตอบที่ถูกต้อง .... ในกรณีที่คนอื่นคิดว่ามันจำเป็นต้องอธิบายให้ดีกว่า

SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL

และฉันเคยเห็นซินแท็กซ์ใน FROM ซึ่งจำเป็นต้องใช้เครื่องหมายจุลภาคระหว่างชื่อตารางใน mySQL แต่ใน sqlLite ดูเหมือนว่าจะชอบพื้นที่มากกว่า

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


0

หากคุณต้องการเลือกเฉพาะผู้ใช้

SELECT tent_nmr FROM Statio_Tentative_Mstr
WHERE tent_npk = '90009'
AND
tent_nmr NOT IN (SELECT permintaan_tent FROM Statio_Permintaan_Mstr)

tent_npkเป็นคีย์หลักของผู้ใช้

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