คำเตือนเกี่ยวกับการแก้ปัญหา:
โซลูชั่นที่มีอยู่มากมายจะให้ผลลัพธ์ที่ไม่ถูกต้องหากแถวไม่ได้มีลักษณะเฉพาะ
หากคุณเป็นคนเดียวที่สร้างตารางสิ่งนี้อาจไม่เกี่ยวข้องกัน แต่โซลูชันหลายอย่างจะให้จำนวนแถวที่แตกต่างจากรหัสที่เป็นปัญหาเมื่อหนึ่งในตารางอาจไม่มีแถวที่ไม่ซ้ำกัน
คำเตือนเกี่ยวกับงบปัญหา:
ด้วยคอลัมน์หลายอันนั้นไม่มีอยู่ลองคิดดูว่าคุณต้องการอะไรอย่างระมัดระวัง
เมื่อฉันเห็นคอลัมน์สองคอลัมน์ฉันสามารถจินตนาการได้ว่ามันหมายถึงสองสิ่ง:
- ค่าของคอลัมน์ a และคอลัมน์ b ปรากฏในตารางอื่นอย่างอิสระ
- ค่าของคอลัมน์ a และคอลัมน์ b ปรากฏในตารางอื่นพร้อมกันในแถวเดียวกัน
สถานการณ์ที่ 1 ค่อนข้างน่าสนใจเพียงใช้สองข้อความสั่ง
เพื่อให้สอดคล้องกับคำตอบที่มีอยู่ส่วนใหญ่ฉันขออธิบายภาพรวมของวิธีการที่กล่าวถึงและเพิ่มเติมสำหรับสถานการณ์จำลอง 2 (และการตัดสินโดยย่อ):
EXISTS (ปลอดภัยแนะนำสำหรับ SQL Server)
จัดหาโดย @mrdenny EXISTS ฟังดูเหมือนสิ่งที่คุณกำลังมองหานี่คือตัวอย่างของเขา:
SELECT * FROM T1
WHERE EXISTS
(SELECT * FROM T2
WHERE T1.a=T2.a and T1.b=T2.b)
ซ้าย SEMI เข้าร่วม (ปลอดภัยแนะนำสำหรับภาษาที่รองรับ)
นี่เป็นวิธีที่รัดกุมมากในการเข้าร่วม แต่น่าเสียดายที่ภาษา SQL ส่วนใหญ่รวมถึงเซิร์ฟเวอร์ SQL ไม่สนับสนุนในปัจจุบัน
SELECT * FROM T1
LEFT SEMI JOIN T2 ON T1.a=T2.a and T1.b=T2.b
คำสั่ง IN จำนวนมาก (ปลอดภัย แต่ระวังการทำสำเนารหัส)
ดังที่ @cataclysm ที่ใช้คำสั่ง IN สองข้อสามารถทำเคล็ดลับได้เช่นกันบางทีมันอาจจะดีกว่าโซลูชันอื่น ๆ อย่างไรก็ตามสิ่งที่คุณควรระวังอย่างยิ่งคือการทำสำเนารหัส หากคุณต้องการเลือกจากตารางอื่นหรือเปลี่ยนคำสั่ง where เป็นความเสี่ยงที่เพิ่มขึ้นที่คุณสร้างความไม่สอดคล้องกันในตรรกะของคุณ
โซลูชันพื้นฐาน
SELECT * from T1
WHERE a IN (SELECT a FROM T2 WHERE something)
AND b IN (SELECT b FROM T2 WHERE something)
โซลูชันที่ไม่มีการทำสำเนารหัส (ฉันเชื่อว่านี่จะไม่ทำงานในการสืบค้น SQL Server ปกติ)
WITH mytmp AS (SELECT a, b FROM T2 WHERE something);
SELECT * from T1
WHERE a IN (SELECT a FROM mytmp)
AND b IN (SELECT b FROM mytmp)
เข้าร่วมภายใน (ในทางเทคนิคสามารถทำให้ปลอดภัย แต่บ่อยครั้งที่สิ่งนี้ไม่ได้ทำ)
เหตุผลที่ฉันไม่แนะนำให้ใช้การรวมภายในเป็นตัวกรองเนื่องจากในทางปฏิบัติผู้คนมักปล่อยให้ข้อมูลซ้ำในตารางด้านขวาทำให้เกิดการซ้ำซ้อนในตารางด้านซ้าย และเพื่อให้เรื่องแย่ลงบางครั้งพวกเขาทำให้ผลลัพธ์สุดท้ายชัดเจนในขณะที่ตารางด้านซ้ายอาจไม่จำเป็นต้องมีลักษณะเฉพาะ (หรือไม่ซ้ำกันในคอลัมน์ที่คุณเลือก) ยิ่งกว่านั้นมันให้โอกาสคุณในการเลือกคอลัมน์ที่ไม่มีอยู่จริงในตารางด้านซ้าย
SELECT T1.* FROM T1
INNER JOIN
(SELECT DISTINCT a, b FROM T2) AS T2sub
ON T1.a=T2sub.a AND T1.b=T2sub.b
ข้อผิดพลาดที่พบบ่อยที่สุด:
- เข้าร่วมโดยตรงกับ T2 โดยไม่มีแบบสอบถามย่อยที่ปลอดภัย ส่งผลให้เกิดความเสี่ยงในการทำซ้ำ)
- SELECT * (รับประกันเพื่อรับคอลัมน์จาก T2)
- เลือก c (ไม่รับประกันว่าคอลัมน์ของคุณจะมาจาก T1 เสมอ)
- ไม่มี DISTINCT หรือ DISTINCT ในตำแหน่งที่ไม่ถูกต้อง
การจัดเรียงของคอลัมน์กับตัวแยก (ไม่ปลอดภัยมากประสิทธิภาพที่น่ากลัว)
ปัญหาการทำงานคือถ้าคุณใช้ตัวคั่นที่อาจเกิดขึ้นในคอลัมน์มันจะยุ่งยากเพื่อให้แน่ใจว่าผลลัพธ์นั้นถูกต้อง 100% ปัญหาทางเทคนิคคือวิธีนี้มักจะเกิดการแปลงประเภทและไม่สนใจดัชนีอย่างสมบูรณ์ซึ่งส่งผลให้เกิดประสิทธิภาพที่แย่ แม้จะมีปัญหาเหล่านี้ฉันต้องยอมรับว่าบางครั้งฉันยังคงใช้มันสำหรับการสืบค้นเฉพาะกิจในชุดข้อมูลขนาดเล็ก
SELECT * FROM T1
WHERE CONCAT(a,"_",b) IN
(SELECT CONCAT(a,"_",b) FROM T2)
โปรดทราบว่าหากคอลัมน์ของคุณเป็นตัวเลขภาษา SQL บางภาษาจะต้องให้คุณแปลงเป็นสตริงก่อน ฉันเชื่อว่าเซิร์ฟเวอร์ SQL จะทำสิ่งนี้โดยอัตโนมัติ
ในการสรุป: ตามปกติมีหลายวิธีในการใช้ SQL การใช้ตัวเลือกที่ปลอดภัยจะช่วยหลีกเลี่ยงการแปลกใหม่และประหยัดเวลาและส่วนหัวในระยะยาว