ฉันเห็นคนจำนวนมากใช้คิวรีย่อยหรือคุณสมบัติเฉพาะของผู้จำหน่ายเพื่อทำสิ่งนี้ แต่ฉันมักจะทำคิวรีประเภทนี้โดยไม่มีคิวรีย่อยในวิธีต่อไปนี้ มันใช้ธรรมดา SQL มาตรฐานดังนั้นมันควรจะทำงานในทุกยี่ห้อของ RDBMS
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON (t1.UserId = t2.UserId AND t1."Date" < t2."Date")
WHERE t2.UserId IS NULL;
กล่าวอีกนัยหนึ่ง: ดึงแถวจากt1
ที่ไม่มีแถวอื่นที่มีวันเดียวกันUserId
และวันที่มากกว่า
(ฉันใส่ตัวระบุ "วันที่" ในตัวคั่นเพราะเป็นคำที่สงวนไว้ของ SQL)
ในกรณีที่t1."Date" = t2."Date"
ปรากฏเป็นสองเท่า มักจะมีตารางที่สำคัญเช่นauto_inc(seq)
id
เพื่อหลีกเลี่ยงการเสแสร้งสามารถใช้ได้ดังนี้:
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON t1.UserId = t2.UserId AND ((t1."Date" < t2."Date")
OR (t1."Date" = t2."Date" AND t1.id < t2.id))
WHERE t2.UserId IS NULL;
ความคิดเห็นอีกครั้งจาก @Farhan:
นี่คือคำอธิบายโดยละเอียดเพิ่มเติม:
การเข้าร่วม outer ความพยายามในการที่จะเข้าร่วมกับt1
t2
ตามค่าเริ่มต้นผลลัพธ์ทั้งหมดt1
จะถูกส่งคืนและหากมีการจับคู่ที่ตรงกันผลลัพธ์t2
ก็จะถูกส่งคืนเช่นกัน หากไม่มีการจับคู่ในt2
แถวที่ระบุt1
แสดงว่าแบบสอบถามยังคงส่งคืนแถวt1
และใช้NULL
เป็นตัวยึดตำแหน่งสำหรับt2
คอลัมน์ทั้งหมดของ นั่นเป็นเพียงวิธีที่การรวมภายนอกทำงานโดยทั่วไป
เคล็ดลับในแบบสอบถามนี้คือการออกแบบเข้าร่วมสภาพจับคู่ดังกล่าวว่าt2
จะต้องตรงกับที่เหมือนกัน userid
และมากขึ้น date
คิดถูกถ้าแถวมีอยู่ในt2
ที่มีมากขึ้นdate
แล้วแถวในt1
มันเทียบกับการไม่สามารถเป็นคนที่ยิ่งใหญ่ที่สุดสำหรับการที่date
userid
แต่ถ้าไม่มีการแข่งขัน - คือถ้าไม่มีแถวที่มีอยู่ในt2
ที่มีมากขึ้นdate
กว่าแถวในt1
- เรารู้ว่าแถวในt1
เป็นแถวที่มีที่ยิ่งใหญ่ที่สุดสำหรับการที่ได้รับdate
userid
ในกรณีเหล่านั้น (เมื่อไม่มีการจับคู่) คอลัมน์ของt2
จะเป็นNULL
- แม้แต่คอลัมน์ที่ระบุในเงื่อนไขการเข้าร่วม เพื่อที่ว่าทำไมเราใช้WHERE t2.UserId IS NULL
เพราะเรากำลังค้นหาสำหรับกรณีที่ไม่มีแถวก็พบว่ามีมากขึ้นสำหรับการที่ได้รับdate
userid