ฉันได้แก้ไขปัญหาการสืบค้นโดยใช้ ... row_number() over (partition by
... นี่เป็นคำถามทั่วไปเพิ่มเติมเกี่ยวกับสาเหตุที่เราไม่สามารถใช้คอลัมน์ที่มีค่า Null ในการเข้าร่วมได้ เหตุใดค่าโมฆะจึงไม่เท่ากับค่าว่างเพื่อการเข้าร่วม?
ฉันได้แก้ไขปัญหาการสืบค้นโดยใช้ ... row_number() over (partition by
... นี่เป็นคำถามทั่วไปเพิ่มเติมเกี่ยวกับสาเหตุที่เราไม่สามารถใช้คอลัมน์ที่มีค่า Null ในการเข้าร่วมได้ เหตุใดค่าโมฆะจึงไม่เท่ากับค่าว่างเพื่อการเข้าร่วม?
คำตอบ:
เหตุใดค่าโมฆะจึงไม่เท่ากับค่าว่างสำหรับการเข้าร่วม?
เพียงบอกให้ Oracle ทำเช่นนั้น:
select *
from one t1
join two t2 on coalesce(t1.id, -1) = coalesce(t2.id, -1);
(โปรดทราบว่าใน SQL มาตรฐานคุณสามารถใช้t1.id is not distinct from t2.id
เพื่อรับโอเปอเรเตอร์ความปลอดภัยแบบ null-safe แต่ Oracle ไม่รองรับสิ่งนั้น)
แต่วิธีนี้จะใช้ได้เฉพาะในกรณีที่ค่าการแทนที่ (-1 ในตัวอย่างด้านบน) ไม่ปรากฏในตาราง การค้นหาค่า "วิเศษ" สำหรับตัวเลขอาจเป็นไปได้ แต่จะยากมากสำหรับค่าอักขระ (โดยเฉพาะอย่างยิ่งเนื่องจาก Oracle ปฏิบัติต่อสตริงว่างnull
เช่นกัน)
บวก: จะไม่มีการใช้ดัชนีในid
คอลัมน์ (คุณสามารถกำหนดดัชนีตามฟังก์ชันโดยใช้coalesce()
นิพจน์)
ตัวเลือกอื่นที่ใช้ได้กับทุกประเภทโดยไม่มีค่าเวทย์มนตร์:
on t1.id = t2.id or (t1.id is null and t2.id is null)
แต่คำถามที่แท้จริงคือ: มันสมเหตุสมผลหรือไม่
พิจารณาข้อมูลตัวอย่างต่อไปนี้:
ตารางที่หนึ่ง
id
----
1
2
(null)
(null)
ตารางที่สอง
id
----
1
2
(null)
(null)
(null)
ควรเลือกการรวมกันของค่า Null ใดในการเข้าร่วม ตัวอย่างด้านบนของฉันจะส่งผลให้มีค่า cross สำหรับการเข้าร่วมทั้งหมด
T1_ID | T2_ID
-------+-------
1 | 1
2 | 2
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
อีกวิธีหนึ่งคุณสามารถทำให้ค่า Null สองค่าจับคู่กันโดยใช้INTERSECT
เป็นตัวดำเนินการความเสมอภาค:
SELECT
*
FROM
t1
INNER JOIN t2
ON EXISTS (SELECT t1.ID FROM DUAL INTERSECT SELECT t2.ID FROM DUAL)
;
ดูตัวอย่าง DBFiddle นี้สำหรับภาพประกอบ
ของหลักสูตรลักษณะนี้ค่อนข้างคำหนึ่งแม้ว่ามันจะเป็นจริงไม่ได้นานกว่าข้อเสนอแนะของ BriteSponge อย่างไรก็ตามมันไม่แน่นอนถ้าคุณให้อภัยคำพิพากษาถึงความรัดกุมของที่กล่าวถึงก่อนหน้านี้ในวิธีการแสดงความคิดเห็นมาตรฐานซึ่งเป็นIS NOT DISTINCT FROM
ผู้ประกอบการยังไม่ได้รับการสนับสนุนใน Oracle
เพื่อความสมบูรณ์ฉันจะพูดถึงว่าSYS_OP_MAP_NONNULL
ตอนนี้ฟังก์ชั่นสามารถนำมาใช้อย่างปลอดภัยเพื่อเปรียบเทียบค่าที่เป็นโมฆะเพราะตอนนี้มันถูกบันทึกไว้ในเอกสาร 12c ซึ่งหมายความว่า Oracle ไม่เพียง แต่จะลบและทำลายรหัส
SELECT *
FROM one t1
JOIN two t2
ON SYS_OP_MAP_NONNULL(t1.id) = SYS_OP_MAP_NONNULL(t2.id)
ข้อได้เปรียบที่คุณไม่ได้เจอกับปัญหาเรื่อง 'ความมหัศจรรย์'
การอ้างอิงในเอกสารของ Oracle อยู่ที่มุมมองที่เป็นรูปธรรมพื้นฐาน - การเลือกดัชนีสำหรับมุมมองที่ปรากฏ
คุณสามารถเข้าร่วมค่า Null โดยใช้การถอดรหัส:
on decode(t1.id, t2.id, 1, 0) = 1
decode
ถือว่าเป็นโมฆะเท่ากันดังนั้นจึงใช้งานได้โดยไม่ต้องใช้หมายเลข "วิเศษ" สองคอลัมน์ต้องมีชนิดข้อมูลเดียวกัน
มันจะไม่สร้างโค้ดที่อ่านได้มากที่สุด แต่อาจจะยังดีกว่า t1.id = t2.id or (t1.id is null and t2.id is null)
ทำไมคุณไม่สามารถใช้ค่า Null ในการเข้าร่วมได้ ใน Oracle ทั้งสองอย่างต่อไปนี้ไม่ได้ประเมินว่าเป็นจริง:
NULL = NULL
NULL <> NULL
นั่นเป็นเหตุผลที่เราต้องIS NULL
/ IS NOT NULL
เพื่อตรวจสอบค่าว่าง
เพื่อทดสอบสิ่งนี้คุณสามารถทำได้:
SELECT * FROM table_name WHERE NULL = NULL
Joins กำลังประเมินเงื่อนไขบูลีนและพวกเขาไม่ได้ตั้งโปรแกรมให้ทำงานแตกต่างกัน คุณสามารถใส่เครื่องหมายมากกว่าในเงื่อนไขการเข้าร่วมและเพิ่มเงื่อนไขอื่น ๆ มันแค่ประเมินว่ามันเป็นนิพจน์บูลีน
ฉันเดาว่าโมฆะไม่สามารถเท่ากับโมฆะในการเข้าร่วมเพื่อประโยชน์ของความสอดคล้อง มันจะท้าทายพฤติกรรมปกติของผู้ประกอบการเปรียบเทียบ
NULL = anything
ผลลัพธ์เป็นNULL
เพราะมาตรฐาน SQL บอกเช่นนั้น แถวเป็นไปตามเงื่อนไขการเข้าร่วมเฉพาะในกรณีที่นิพจน์เป็นจริง
ค่า Null ในฐานข้อมูลเชิงสัมพันธ์ส่วนใหญ่ถือว่า UNKNOWN ไม่ควรสับสนกับศูนย์ HEX ทั้งหมด หากบางสิ่งมีโมฆะ (ไม่ทราบ) คุณไม่สามารถเปรียบเทียบได้
Unknown = Known False
Unknown = Unknown False
Unknown >= Known False
Known >= Unknown False
ซึ่งหมายความว่าเมื่อใดก็ตามที่คุณมีโมฆะในฐานะตัวถูกดำเนินการในนิพจน์บูลีนส่วนอื่นจะเป็นจริงเสมอ
ตรงกันข้ามกับความเกลียดชังทั่วไปที่มีต่อ null โดยนักพัฒนา null มีสถานที่ หากสิ่งที่ไม่รู้จักใช้ null
UNKNOWN
ไม่ใช่FALSE
;)
where (a = b or (a is null and b is null))
จุดนั่นคือความคิดของฉันเกี่ยวกับมันฉันจะไม่พิจารณาการใช้sys_op_map_nonnull
งานไม่สนใจคนที่อยู่หลังม่าน