SQL จะทำให้ค่า null เป็นอย่างไรเมื่อเรียงลำดับจากน้อยไปมาก


297

ฉันมีตาราง SQL ที่มีเขตข้อมูลวันที่และเวลา ฟิลด์ที่เป็นปัญหาอาจเป็นโมฆะ ฉันมีแบบสอบถามและฉันต้องการผลลัพธ์เรียงจากน้อยไปมากโดยเขตข้อมูลวันที่และเวลา แต่ฉันต้องการแถวที่เขตข้อมูลวันที่และเวลาเป็นโมฆะในตอนท้ายของรายการไม่ใช่ตอนเริ่มต้น

มีวิธีง่ายๆในการทำเช่นนั้นหรือไม่?


5
สำเนาซ้ำซ้อนของstackoverflow.com/questions/151195/…
Bill Karwin

คำตอบ:


394
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate

2
อย่างไรก็ตามโปรดทราบว่าหากคุณวางดัชนีในคอลัมน์เรียงลำดับเพื่อปรับปรุงประสิทธิภาพ (*) วิธีนี้จะทำให้แผนแบบสอบถามค่อนข้างซับซ้อนและสูญเสียผลประโยชน์ด้านประสิทธิภาพเป็นจำนวนมาก * - ดัชนีจัดเตรียมข้อมูลไว้ล่วงหน้าจึงหลีกเลี่ยงการดำเนินการเรียงลำดับต่อแบบสอบถาม ขอแนะนำให้กรองระเบียน NULL ถ้าเป็นไปได้เพื่อหลีกเลี่ยงปัญหานี้อย่างสมบูรณ์
redcalx

2
คำตอบที่ดียังได้รับที่นี่ด้วยวิธีที่เป็นไปได้ทั้งหมดด้วยความได้เปรียบและข้อเสีย nickstips.wordpress.com/2010/09/30/…
sudhAnsu63

40
order by case when MyDate is null then 1 else 0 end เป็นการพูดที่ยาวมาก ORDER BY MyDate IS NULL
มาร์ติน

5
@ Martin หมายเหตุคำถามนี้ไม่ได้ติดแท็ก mysql ฉันให้วิธีการแก้ปัญหาแบบทั่วไป - มีหลายวิธีในการทำสิ่งเดียวกันทั่ว dBS ที่แตกต่างกัน
RedFilter

1
@KyleDelaney เพราะorder by 0ถูกตีความว่าเป็นดัชนีคอลัมน์และดัชนีคอลัมน์เป็นแบบ 1 ในการจัดเรียงข้อความค้นหาตามคอลัมน์ที่ 3 คุณสามารถพูดได้order by 3(ซึ่งเป็นความคิดที่แย่มากสำหรับคำสั่งการผลิต) แต่มีประโยชน์มาก (เช่นเดิม*) เมื่อทำการทดลอง
RedFilter

159

(A "บิต" ล่าช้า แต่ยังไม่ได้กล่าวถึงทั้งหมด)

คุณไม่ได้ระบุ DBMS ของคุณ

ใน SQL มาตรฐาน (และ DBMS ที่ทันสมัยที่สุดเช่น Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB และ H2) คุณสามารถระบุNULLS LASTหรือNULLS FIRST:

ใช้NULLS LASTเพื่อจัดเรียงพวกเขาไปยังจุดสิ้นสุด:

select *
from some_table
order by some_column DESC NULLS LAST

16
AFAIK NULLS FIRSTและNULLS LASTถูกเพิ่มเข้ามาใน SQL: 2003 แต่ไม่มีการนำมาตรฐานไปใช้งานใน DMBS ที่แตกต่างกัน ' ขึ้นอยู่กับเอ็นจิ้นฐานข้อมูลใช้ORDER BY expr some_column DESC NULLS LAST(Oracle), ORDER BY ISNULL(some_column, 1), some_column ASC(MSSQL) หรือORDER BY ISNULL(some_column), some_column ASC(MySQL ด้วยการใช้ ISNULL () ที่แตกต่างกัน)
SaschaM78

3
@ SaschaM78: การเรียงลำดับเริ่มต้นของ NULLs ขึ้นอยู่กับ DBMS บางคนจัดเรียงพวกเขาในตอนท้ายบางคนที่จุดเริ่มต้น บางคนไม่ต้องกังวลเกี่ยวกับASC/ DESCด้วย nulls บางคนทำ ดังนั้นวิธีเดียวที่จะทำให้แน่ใจได้คือใช้NULL FIRST/LAST ถ้า DBMS รองรับ ที่เอกสารสิ่งที่คุณตั้งใจ การใช้งานisnull()หรือฟังก์ชั่นอื่น ๆ เป็นวิธีแก้ปัญหาสำหรับการสนับสนุนที่ขาดหายไปNULLS FIRST/LAST(ซึ่งถูกแทนที่โดย Oracle, PostgreSQL, DB2, Firebird, Apache Derby, HSQLDB และ H2)
a_horse_with_no_name

คุณพูดถูกฉันต้องการเพิ่มข้อเท็จจริงที่ว่ามีบางส่วนของ DBMS ที่ไม่เป็นไปตามมาตรฐาน (หรือ) หรือมีความเชี่ยวชาญเช่น Oracle ที่ต้องการexprคำหลักเมื่อใช้ NULLS FIRST / LAST และขอขอบคุณเกี่ยวกับค่า null ที่แสดงครั้งแรก / ครั้งสุดท้ายที่แตกต่างจากประเภทฐานข้อมูลเป็นประเภทไม่รู้ว่า!
SaschaM78

2
ดูเหมือนว่าจะมีแนวโน้ม แต่น่าเศร้าที่ฉันลองใช้งานและNULLS LASTไม่ได้ทำงานในฐานข้อมูล MySQL ของฉัน
AdmiralThrawn

1
@AdmiralAdama: คุณสามารถอัปเกรดเป็น Postgres ได้ตลอดเวลา
a_horse_with_no_name

35

ฉันเพิ่งเจอสิ่งนี้และสิ่งต่อไปนี้ดูเหมือนจะใช้เคล็ดลับสำหรับฉันใน MySQL และ PostgreSQL:

ORDER BY date IS NULL, date DESC

พบได้ที่https://stackoverflow.com/a/7055259/496209


สิ่งนี้ดูมีแนวโน้ม แต่น่าเศร้าที่ฉันลองใช้IS NULLและIS NOT NULLไม่ได้ทำงานในฐานข้อมูล MySQL ของฉัน
AdmiralThrawn

14
order by coalesce(date-time-field,large date in future)

10
แม้ว่าโดยทั่วไปจะใช้งานได้ แต่ควรสังเกตว่าคำตอบนี้มีปัญหาเล็กน้อย: วันที่ที่มีขนาดใหญ่ในอนาคตอาจชนหรือน้อยกว่าข้อมูลจริงส่งผลให้เกิดการเรียงลำดับที่ไม่สมบูรณ์ นอกจากนี้ยังเป็นโซลูชัน "หมายเลขมายากล" ที่ไม่ได้จัดทำเอกสารด้วยตนเอง
RedFilter

นี่เป็นทางเลือกที่ยอดเยี่ยมสำหรับคำตอบ @RedFilter เมื่อคุณต้องการเปรียบเทียบคอลัมน์ที่เป็นปัญหากับคอลัมน์วันที่อื่น ฉันใช้รายการนี้สำหรับรายการระดับอาวุโสสหภาพ หากพนักงานมีวันที่ผ่านการรับรอง (ซึ่งเป็นโมฆะ) วันที่นั้นจะบันทึกฟองอากาศไว้ด้านบนหรือใช้ HireDate ใช้ ORDER BY ISNULL (QualifiedDate, '1-1-2099'), HireDate, LastName และอื่น ๆ ทำให้วันที่ผ่านการรับรองไม่ขัดแย้งกับวันที่ HiredDate และรายการ Senirity ที่ถูกต้องถูกสร้างขึ้น
อลันฟิชเชอร์

14

คุณสามารถใช้ฟังก์ชันในตัวเพื่อตรวจสอบค่าว่างหรือไม่ว่างดังต่อไปนี้ ฉันทดสอบและทำงานได้ดี

select MyDate from MyTable order by ISNULL(MyDate,1) DESC, MyDate ASC;


สำหรับวันที่จะทำงานกับ mssql ฉันพบว่ามีประโยชน์ในการวางอนาคตในฟังก์ชัน ISNULL เช่น ISNULL (MyDate, '2100-01-01')
Emi-C

ใน MySQL มันบอกว่าฉันผ่านพารามิเตอร์มากเกินไป ฉันได้สิ่งนี้เพื่อแยกวิเคราะห์โดยทำISNULL(MyDate) DESC, MyDate ASCแต่มันไม่ได้เรียงตามลำดับที่ถูกต้อง
AdmiralThrawn

12

หากเครื่องยนต์ของคุณอนุญาตORDER BY x IS NULL, xหรือORDER BY x NULLS LASTใช้งาน แต่หากไม่เป็นเช่นนั้นก็อาจช่วยได้:

หากคุณเรียงลำดับตามประเภทตัวเลขคุณสามารถทำได้: (ยืมสคีมาจากคำตอบอื่น )

SELECT *          
FROM Employees
ORDER BY ISNULL(DepartmentId*0,1), DepartmentId;

ผลลัพธ์แสดงเรียงตาม DepartmentId พร้อม nulls ล่าสุด

หมายเลขที่ไม่ใช่ค่าว่างใด ๆ จะกลายเป็น 0 และค่า Null กลายเป็น 1 ซึ่งเรียงลำดับค่า Null เป็นครั้งสุดท้าย

คุณยังสามารถทำสิ่งนี้เพื่อสตริง:

SELECT *
FROM Employees
ORDER BY ISNULL(LEFT(LastName,0),'a'), LastName

ผลลัพธ์แสดงเรียงตามนามสกุลด้วยค่า null ล่าสุด

เพราะ>'a'''

สิ่งนี้สามารถทำงานร่วมกับวันที่ได้ด้วยการบังคับให้ int เป็นโมฆะและใช้วิธีการสำหรับ ints ข้างต้น:

SELECT *
FROM Employees
ORDER BY ISNULL(CONVERT(INT, HireDate)*0, 1), HireDate

(ยอมให้คีมามี HireDate)

วิธีการเหล่านี้หลีกเลี่ยงปัญหาที่ต้องเกิดขึ้นหรือจัดการค่า "สูงสุด" ของทุกชนิดหรือแก้ไขแบบสอบถามถ้าการเปลี่ยนแปลงชนิดข้อมูล (และสูงสุด) (ทั้งปัญหาที่ ISNULL อื่น ๆ ประสบปัญหา) นอกจากนี้ยังสั้นกว่า CASE มาก


ใช้งานได้ดี! ขอบคุณ
Vani

8

เมื่อคอลัมน์คำสั่งซื้อของคุณเป็นตัวเลข (เช่นอันดับ) คุณสามารถคูณมันด้วย -1 จากนั้นเรียงลำดับจากมากไปน้อย มันจะรักษาคำสั่งที่คุณกำลัง expecing แต่ใส่ NULL ล่าสุด

select *
from table
order by -rank desc

กำลังจะแสดงความคิดเห็นนี้ เรียนรู้จากstackoverflow.com/a/8174026/1193304และเยี่ยมยอดมาก
Chris


3

ขอบคุณ RedFilter สำหรับการมอบทางออกที่ยอดเยี่ยมให้กับปัญหาการคัดแยกของการจัดเรียงเขตข้อมูลวันและเวลาที่ไม่มีค่า

ฉันใช้ฐานข้อมูล SQL Server สำหรับโครงการของฉัน

การเปลี่ยนค่าศูนย์ข้อมูลเป็น "1" จะช่วยแก้ปัญหาการเรียงลำดับสำหรับคอลัมน์ประเภทข้อมูลวันที่และเวลา อย่างไรก็ตามหากเรามีคอลัมน์ที่มีประเภทข้อมูลอื่นนอกเหนือจาก datetime แล้วมันไม่สามารถจัดการได้

เพื่อจัดการเรียงคอลัมน์ varchar ฉันพยายามใช้ 'ZZZZZZZ' เพราะฉันรู้ว่าคอลัมน์ไม่มีค่าที่ขึ้นต้นด้วย 'Z' มันทำงานได้ตามที่คาดไว้

ในบรรทัดเดียวกันฉันใช้ค่าสูงสุด +1 สำหรับประเภทข้อมูล int และอื่น ๆ เพื่อรับการจัดเรียงตามที่คาดไว้ สิ่งนี้ยังให้ผลลัพธ์ตามที่ฉันต้องการ

อย่างไรก็ตามมันจะเหมาะอย่างยิ่งที่จะทำให้บางสิ่งง่ายขึ้นในเอ็นจินฐานข้อมูลเองที่สามารถทำสิ่งต่อไปนี้:

Order by Col1 Asc Nulls Last, Col2 Asc Nulls First 

ตามที่ระบุไว้ในคำตอบที่จัดทำโดย a_horse_with_no_name



3

หากคุณกำลังใช้ MariaDB พวกเขาพูดถึงต่อไปนี้ในเอกสารโมฆะค่า

การสั่งซื้อ

เมื่อคุณสั่งซื้อตามเขตข้อมูลที่อาจมีค่าเป็นศูนย์ค่า NULL ใด ๆ จะถือว่ามีค่าต่ำสุด ดังนั้นการสั่งซื้อตามลำดับ DESC จะเห็นค่า NULL ปรากฏขึ้นครั้งสุดท้าย เมื่อต้องการบังคับให้ NULL ถือเป็นค่าสูงสุดหนึ่งสามารถเพิ่มคอลัมน์อื่นที่มีค่าสูงกว่าเมื่อเขตข้อมูลหลักเป็น NULL ตัวอย่าง:

SELECT col1 FROM tab ORDER BY ISNULL(col1), col1;

ลำดับจากมากไปน้อยด้วย NULL ก่อน:

SELECT col1 FROM tab ORDER BY IF(col1 IS NULL, 0, 1), col1 DESC;

ค่า NULL ทั้งหมดยังได้รับการพิจารณาว่าเทียบเท่ากับวัตถุประสงค์ของ DISTINCT และ GROUP BY clauses

ด้านบนแสดงสองวิธีในการสั่งซื้อด้วยค่า NULL คุณสามารถรวมเหล่านี้เข้ากับคำหลัก ASC และ DESC ได้เช่นกัน ตัวอย่างเช่นวิธีอื่นในการรับค่า NULL ก่อนจะเป็น:

SELECT col1 FROM tab ORDER BY ISNULL(col1) DESC, col1;
--                                         ^^^^

2

การแก้ปัญหาโดยใช้ "case" นั้นเป็นเรื่องทั่วไป แต่ไม่ใช้ดัชนี

order by case when MyDate is null then 1 else 0 end, MyDate

ในกรณีของฉันฉันต้องการประสิทธิภาพ

 SELECT smoneCol1,someCol2  
 FROM someSch.someTab
 WHERE someCol2 = 2101 and ( someCol1 IS NULL ) 
  UNION   
 SELECT smoneCol1,someCol2
 FROM someSch.someTab
 WHERE someCol2 = 2101 and (  someCol1 IS NOT NULL)  

1
UNION ALLหากคุณมีความสนใจในการทำงานของคุณควรจะใช้
RedFilter


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