Sql-Server

查詢以基於“時間”列對行進行分類,而不使用 CASE 表達式

  • October 29, 2020

有一個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:mm003000: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(在計算中使用而不是凌亂的字元串操作,上面的查詢不那麼複雜,而且,作為獎勵,您可以獲得內置驗證,以避免像1369and這樣的無效時間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;

引用自:https://dba.stackexchange.com/questions/237015