แบบสอบถาม SQL เพื่อค้นหาเรกคอร์ดที่มี ID ไม่อยู่ในตารางอื่น


123

ฉันมีตารางสองตารางที่มีคีย์หลักที่ผูกไว้ในฐานข้อมูลและฉันต้องการค้นหาชุดที่ไม่ปะติดปะต่อระหว่างพวกเขา ตัวอย่างเช่น,

  • Table1มีคอลัมน์ ( ID, Name) และข้อมูลตัวอย่าง:(1 ,John), (2, Peter), (3, Mary)
  • Table2มีคอลัมน์ ( ID, Address) และข้อมูลตัวอย่าง:(1, address2), (2, address2)

ดังนั้นวิธีที่ฉันจะสร้างแบบสอบถาม SQL เพื่อให้สามารถดึงข้อมูลแถวที่มี ID จากที่ไม่ได้อยู่ในtable1 table2กรณีนี้(3, Mary)ควรส่งคืนหรือไม่?

ps ID เป็นคีย์หลักสำหรับสองตารางนั้น

ขอบคุณล่วงหน้า.


3
เพื่อเป็นเคล็ดลับสำหรับคำถามในอนาคต: กำหนดระบบฐานข้อมูล (และเวอร์ชันของฐานข้อมูลนั้น) ที่คุณใช้อยู่เสมอ SQLเป็นเพียงStructured Query Language ที่ใช้โดยระบบฐานข้อมูลส่วนใหญ่ซึ่งไม่ได้ช่วยอะไรมากนัก ... บ่อยครั้งที่ฐานข้อมูลมีส่วนขยายและคุณลักษณะที่นอกเหนือไปจากมาตรฐาน ANSI / ISO SQL ซึ่งทำให้การแก้ปัญหาเป็นเรื่องง่าย - แต่สำหรับสิ่งนั้นคุณ ต้องบอกเราว่าคุณใช้ฐานข้อมูลอะไร
marc_s

5
@marc_s: จะเกิดอะไรขึ้นถ้าพวกเขากำลังมองหาโซลูชันที่ไม่เชื่อเรื่องพระเจ้าเพราะพวกเขาจำเป็นต้องรองรับระบบฐานข้อมูลพื้นฐานหลายระบบหรือการใช้งานฐานข้อมูลจะถูกแยกออกไป?
dwanderson

สวัสดี @marc_s ฉันใช้ PostgreSQL ในกรณีนี้ ขอบคุณสำหรับการแจ้งเตือน
johnklee

คำตอบ:


213

ลองทำตามนี้

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)

8
@PrinceJea จริงๆแล้วมันขึ้นอยู่กับ ดูคำชี้แจงที่นี่
John Woo

เมื่อฉันมีข้อมูล 20 รายการมันใช้งานได้ แต่เมื่อฉันมีข้อมูล 20000 มันไม่ทำงานตอนนี้ฉันสับสน
Frank

1
ไม่มีความคิดว่าทำไม แต่มันไม่ทำงาน ฉันมีแถวในตารางประมาณ 10,000 แถว ในกรณีของฉันวิธีแก้ปัญหาของ @JohnWoo ทำงานได้ดี
Munam Yousuf

4
จะใช้ไม่ได้กับเรามีค่ามากเกินไปใน "Not In" เนื่องจากวิธีนี้มีค่าจำนวน จำกัด cf: dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato

2
ฉันต้องทำแบบนี้: เลือกฉันจาก Table1 ที่ฉันไม่อยู่ (เลือกฉันจาก Table2 โดยที่ฉันไม่เป็นโมฆะ ) และฉันไม่เป็นโมฆะ
jaksco

93

ใช้ LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL

ฉันคิดว่านี่เป็นแนวทางที่เร็วกว่าสำหรับฐานข้อมูลขนาดใหญ่มาก
Alex Jolig

12

โดยทั่วไปมี 3 วิธีการว่าnot exists, และnot inleft join / is null

ซ้ายเข้าร่วมกับ IS NULL

SELECT  l.*
FROM    t_left l
LEFT JOIN
        t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

ไม่ได้อยู่ใน

SELECT  l.*
FROM    t_left l
WHERE   l.value NOT IN
        (
        SELECT  value
        FROM    t_right r
        )

ไม่มีอยู่

SELECT  l.*
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    t_right r
        WHERE   r.value = l.value
        )

อันไหนดีกว่า? คำตอบสำหรับคำถามนี้อาจจะดีกว่าหากแยกย่อยไปยังผู้ให้บริการ RDBMS รายใหญ่โดยเฉพาะ โดยทั่วไปเราควรหลีกเลี่ยงการใช้select ... where ... in (select...)เมื่อไม่ทราบขนาดของจำนวนระเบียนในแบบสอบถามย่อย ผู้ขายบางรายอาจ จำกัด ขนาด Oracle, ตัวอย่างเช่นมีวงเงิน 1,000 สิ่งที่ดีที่สุดที่ควรทำคือลองทั้งสามอย่างและแสดงแผนการดำเนินการ

รูปแบบเฉพาะของ PostgreSQL แผนการดำเนินการNOT EXISTSและLEFT JOIN / IS NULLเหมือนกัน ฉันชอบNOT EXISTSตัวเลือกนี้เป็นการส่วนตัวเพราะแสดงเจตนาได้ดีกว่า หลังจากที่ทุกความหมายก็คือว่าคุณต้องการที่จะหาระเบียนในที่ PK มันไม่ได้อยู่ใน B

เก่า แต่ยังคงเป็นสีทองเฉพาะสำหรับ PostgreSQL แม้ว่า: https://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/


10

ทางเลือกที่รวดเร็ว

ฉันทำการทดสอบบางอย่าง (ใน postgres 9.5) โดยใช้สองตารางที่มีแถวละ ~ 2M คำค้นหาด้านล่างนี้ทำงานได้ดีกว่าคำค้นหาอื่น ๆ อย่างน้อย 5 * ที่เสนอ:

-- Count
SELECT count(*) FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2;

-- Get full row
SELECT table1.* FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2 JOIN table1 ON t1_not_in_t2.id=table1.id;

1
นี่ไม่ได้เร็วไปกว่าการแก้ปัญหาของ @Jhon Woo ฉันใช้ Postgres 9.6 และด้วยรันไทม์โซลูชันของ Jhon คือประมาณ 60ms ในขณะที่ฉันค่อนข้างแก้ปัญหานี้หลังจาก 120 วินาทีและไม่มีผลลัพธ์
froy001

5

โปรดทราบถึงประเด็นที่อยู่ในความคิดเห็น / ลิงก์ของ @John Woo ด้านบนนี่คือวิธีที่ฉันมักจะจัดการ:

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)

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