นี่คือส่วนขยายของโซลูชันของ Lennartแต่ก็น่าเกลียดจนฉันไม่กล้าแนะนำว่าเป็นการแก้ไข เป้าหมายที่นี่คือการรับผลลัพธ์โดยไม่มีตารางที่ได้รับ อาจไม่จำเป็นสำหรับสิ่งนั้นและเมื่อรวมกับความน่าเกลียดของข้อความค้นหาความพยายามทั้งหมดอาจดูเหมือนเป็นความพยายามที่สูญเปล่า ฉันยังต้องการที่จะทำเช่นนี้เป็นแบบฝึกหัดและตอนนี้ต้องการที่จะแบ่งปันผลของฉัน:
SELECT
Col_A,
Col_B,
DistinctCount = DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- 1
- CASE COUNT(Col_B) OVER (PARTITION BY Col_A)
WHEN COUNT( * ) OVER (PARTITION BY Col_A)
THEN 0
ELSE 1
END
FROM
dbo.MyTable
;
ส่วนหลักของการคำนวณคือ (และก่อนอื่นฉันต้องการทราบว่าแนวคิดไม่ใช่ของฉันฉันได้เรียนรู้เกี่ยวกับเคล็ดลับนี้ที่อื่น):
DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- 1
การแสดงออกนี้สามารถนำมาใช้โดยไม่มีการเปลี่ยนแปลงใด ๆ หากค่าในCol_B
มีการรับประกันว่าจะไม่มี null อย่างไรก็ตามหากคอลัมน์สามารถมีค่า Null ได้คุณจะต้องคำนึงถึงสิ่งนั้นและนั่นคือสิ่งที่CASE
นิพจน์นั้นมี มันเปรียบเทียบจำนวนแถวต่อพาร์ติชันกับจำนวนCol_B
ค่าต่อพาร์ติชัน หากตัวเลขแตกต่างกันก็หมายความว่าบางแถวมีค่าเป็นศูนย์Col_B
และดังนั้นการคำนวณเริ่มต้น ( DENSE_RANK() ... + DENSE_RANK() - 1
) จะต้องลดลง 1
โปรดทราบว่าเนื่องจาก- 1
เป็นส่วนหนึ่งของสูตรหลักฉันเลือกที่จะปล่อยไว้อย่างนั้น อย่างไรก็ตามสามารถรวมเข้ากับCASE
นิพจน์ได้จริงในความพยายามที่ไร้ประโยชน์เพื่อทำให้โซลูชันทั้งหมดดูน่าเกลียดน้อยลง:
SELECT
Col_A,
Col_B,
DistinctCount = DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- CASE COUNT(Col_B) OVER (PARTITION BY Col_A)
WHEN COUNT( * ) OVER (PARTITION BY Col_A)
THEN 1
ELSE 2
END
FROM
dbo.MyTable
;
การสาธิตสดนี้ที่db <> fiddle.uk สามารถใช้ในการทดสอบทั้งสองรูปแบบของการแก้ปัญหา