查詢以基於“時間”列對行進行分類,而不使用 CASE 表達式
有一個
ProductTT
表格,如下所示:[dbo].[ProductTT] (ID int , Product Varchar(50) , Time Int)
…其中包含以下行:
1 XX 0030 2 UY 0354 3 YY 0517 4 ZZ 0712 5 WW 0415 6 GG 1112 7 MM 1030 8 HH 0913
注意
time
:列中數據的格式hh:mm
是0030是00:30。我想編寫一個查詢來根據行的
time
值對行進行分類。我需要有 4 個這樣的類別:category1 00 to 03 category2 03 to 06 category3 06 to 09 category4 09 to 12
我需要查看每個類別有多少行。
到目前為止我的嘗試
到目前為止我寫的是這樣的:
With CTE AS (select ID, product, [time], Case When left(time,2)>=00 and left(time,2)< 03 then 'group1' when left(time,2)>=03 and left(time,2)< 06 then 'group2' when left(time,2)>=06 and left(time,2)< 09 then 'group3' when left(time,2)>=09 and left(time,2)<=12 then 'group4' End AS groupID from [dbo].[ProductTT] ) select groupid,count(*) as recordcount from cte group by groupid
我的問題
該查詢工作正常,但我只想知道是否有更好的方法來編寫此查詢並避免使用 CASE 表達式。
您儲存
Time
為 anint
但隨後將其顯示為字元串(帶有前導零)。這些不會被儲存,因此為了執行需要處理前導零的計算,您需要先轉換為字元串(您目前的查詢不這樣做,所以您的查詢不起作用,或者表結構不准確)。由於這是一個線性計算(3 組),您可以CASE
通過簡單地將時間中的前兩位數除以 3 來簡化表達式(並且由於 SQL Server 的整數除法,餘數被丟棄,我們加 1 去從 0-3 到 1-4)。當然,有一個例外,因為您希望 12 PM 位於第 4 組,而不是第 5 組。使用CASE
表達式可以將其留給ELSE
子句,但如果您消除CASE
,您將不得不明確地處理該異常 - 這就是最後的所有COALESCE
/NULLIF
東西。;WITH x AS ( SELECT ID, Product, [Time] = RIGHT('000'+CONVERT(varchar(4),[Time]),4) FROM dbo.ProductTT ), y AS ( SELECT ID, Product, [Time], h = CONVERT(char(2),[Time]) FROM x ) SELECT ID, Product, [Time], [GroupID] = 'group' + CONVERT(char(1),h/3+1-COALESCE(NULLIF(h%11,1)-h%11,1)) FROM y;
結果:
ID Product Time GroupID -- ------- ---- ------- 1 XX 0030 group1 2 UY 0354 group2 3 YY 0517 group2 4 ZZ 0712 group3 5 WW 0415 group2 6 GG 1112 group4 7 MM 1030 group4 8 HH 0913 group4
我強烈建議您使用實際的
time
數據類型,因為它就是為此而設計的。然後您可以DATEPART(HOUR(
在計算中使用而不是凌亂的字元串操作,上面的查詢不那麼複雜,而且,作為獎勵,您可以獲得內置驗證,以避免像1369
and這樣的無效時間9997
。或者,如果前導零很重要,但您不關心驗證,請使用char(4)
而不是int
.我還認為您需要處理下午發生事件的情況。
FWIW 我不確定你為什麼不想在
CASE
這裡使用表達式。當然,還有幾個字元,但查詢實際在做什麼要清楚得多。自我記錄的程式碼比稍微短一些的程式碼更有價值。恕我直言,這更簡單,如果您使用正確的數據類型會更簡單:;WITH x AS ( SELECT ID, Product, [Time] = RIGHT('000'+CONVERT(varchar(4),[Time]),4) FROM dbo.ProductTT ) SELECT ID, Product, [Time], GroupID = 'group' + CASE CONVERT(char(2),[Time])/3 WHEN 0 THEN '1' WHEN 1 THEN '2' WHEN 2 THEN '3' ELSE '4' END FROM x;