今天學習到新知識 - 資料表欄位進行排序時,遇到 NULL 會怎麼辦?茲針對我平時較會遇到的資料庫:ORACLE、MSSQL 及 SQLite 做個整理。

我弄了一個模擬資料表,用 CorpName, StartDate, EndDate 記錄工作履歷:

查詢條件為「仍在職者(離職日為 NULL)最優先,再來比離職日、到職日,較晚的先列」。

ORACLE 的規則是 - NULL 預設 ASC 時最後顯示、DESC 時最先顯示,但可使用 NULLS FIRST、NULLS LAST 改變行為(亦即 ASC 時預設為 NULLS LAST、DESC 時 NULLS FIRST)。參考

因此,ORDER BY EndDate DESC, StartDate DESC 時,DESC 為 NULLS FIRST 最先出現,預設行為即符合我們的要求。

若想改成 NULL 放最後,可寫成 ORDER BY EndDate DESC NULLS LAST, StartDate DESC

MSSQL 在排序時,Null 值會當做最低的可能值來處理。

因此 ORDER BY EndDate ASC 時排最前面,ORDER BY EndDate DESC 時排最後面:

MSSQL 沒 NULLS LAST 語法可用,替代做法是加上一段 CASE WHEN,寫成 ORDER BY CASE WHEN EndDate IS NULL THEN 0 ELSE 1 END, EndDate DESC, StartDate DESC

插花,今天請 ChatGPT 幫我產生範例時,學到一次 INSERT 多筆 VALUES 寫法:參考 (官方文件的範例說明跟 T-SQL 指令對不起來,說明寫五筆 dbo.Departments 但範例是三筆 Production.UnitMeasure,原來不只我寫文章會錯亂 XD,看 Code 就好)

INSERT INTO resume 
VALUES (N'公司A', '2001-01-01', '2002-12-31'),  
       (N'公司B', '2003-01-01', '2005-06-30'),  
       (N'公司C', '2005-07-01', '2010-09-30'),  
       (N'公司D', '2011-01-01', NULL),
	   (N'兼職', '2004-01-01', NULL);  

最後來看 SQLite,SQLite 的行為接近 MSSQL,NULL 視為最小值 (When it comes to sorting, SQLite considers NULL to be smaller than any other value. 參考),也支援上述一次多個 VALUES 寫法。但 SQLite 3.30.0 支援 NULLS FIRST 及 NULLS LAST,故可用 ORDER BY EndDate DESC NULLS FIRST, StartDate DESC 解決:

Summary about null ordering in ORACLE, MSSQL and SQLite.


Comments

# by Ike

推 MSSQL 的新語法,IIF (2016+ 可用) CASE WHEN EndDate IS NULL THEN 0 ELSE 1 END 改 IIF(EndDate IS NULL, 0, 1)

# by 南無阿彌陀佛

MSSQL : select * from resume order by isnull(EndDate,'99991231') desc,StartDate desc

# by Jeffrey

to Ike, IIF 寫法簡潔多了,已筆記,感謝分享。 to 南無阿彌陀佛,ISNULL 寫法簡短,CASE WHEN 語意明確,各有優點。

Post a comment