[英]SQL very ugly GROUP BY
夏令時計算。 我們在下面確實有一個非常丑陋的工作模型。
看到了這一點-SQL-GROUP BY和COALESCE的丑陋組合
如果我們可以設置變量,則此方法不起作用-同樣,已刪除count(*)以說明我們所遇到的問題。
Declare @subtractor int;
select top 10 case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then
Set @subtractor = 5;
else
Set @subtractor = 6;
end
CAST(DATEADD(HH, -@subtractor,LOGGED_TIME) AS date) AS ForDate
, txtW=DATENAME(WEEKDAY, DATEADD(HH, -@subtractor,LOGGED_TIME))
, intW=DATEPART(WEEKDAY, DATEADD(HH, -@subtractor,LOGGED_TIME))
, intH=DATEPART(HOUR, DATEADD(HH, -@subtractor,LOGGED_TIME))
from SUPPORT_DATABASE.dbo.LOG (nolock)
確實可以。.但是,它是一個非常非常丑陋的GROUP BY ..有沒有辦法清理它?
select top 10
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then CAST(dateadd(hh,-5,LOGGED_TIME) AS date) -- DST
else CAST(dateadd(hh,-6,LOGGED_TIME) AS date) -- DST
end as ForDate,
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then DATENAME(WEEKDAY,dateadd(hh,-5,LOGGED_TIME)) -- DST
else DATENAME(WEEKDAY,dateadd(hh,-6,LOGGED_TIME)) -- DST
end as txtW,
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then DATENAME(WEEKDAY,dateadd(hh,-5,LOGGED_TIME)) -- DST
else DATENAME(WEEKDAY,dateadd(hh,-6,LOGGED_TIME)) -- DST
end as intW,
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then DATEPART(HOUR,dateadd(hh,-5,LOGGED_TIME)) -- DST
else DATEPART(HOUR,dateadd(hh,-6,LOGGED_TIME)) -- DST
end as intH
, COUNT(*) AS Totals
FROM SUPPORT_DATABASE.dbo.LOG WITH (nolock)
GROUP BY case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then CAST(dateadd(hh,-5,LOGGED_TIME) AS date) -- DST
else CAST(dateadd(hh,-6,LOGGED_TIME) AS date) -- DST
end,
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then DATENAME(WEEKDAY,dateadd(hh,-5,LOGGED_TIME)) -- DST
else DATENAME(WEEKDAY,dateadd(hh,-6,LOGGED_TIME)) -- DST
end
,
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then DATEPART(WEEKDAY,dateadd(hh,-5,LOGGED_TIME)) -- DST
else DATEPART(WEEKDAY,dateadd(hh,-6,LOGGED_TIME)) -- DST
end,
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then DATEPART(HOUR,dateadd(hh,-5,LOGGED_TIME)) -- DST
else DATEPART(HOUR,dateadd(hh,-6,LOGGED_TIME)) -- DST
end
您可以將其包裝在cte中,這樣就可以使用別名GROUP BY
了:
;WITH cte AS ( select
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then CAST(dateadd(hh,-5,LOGGED_TIME) AS date) -- DST
else CAST(dateadd(hh,-6,LOGGED_TIME) AS date) -- DST
end as ForDate,
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then DATENAME(WEEKDAY,dateadd(hh,-5,LOGGED_TIME)) -- DST
else DATENAME(WEEKDAY,dateadd(hh,-6,LOGGED_TIME)) -- DST
end as txtW,
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then DATENAME(WEEKDAY,dateadd(hh,-5,LOGGED_TIME)) -- DST
else DATENAME(WEEKDAY,dateadd(hh,-6,LOGGED_TIME)) -- DST
end as intW,
case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then DATEPART(HOUR,dateadd(hh,-5,LOGGED_TIME)) -- DST
else DATEPART(HOUR,dateadd(hh,-6,LOGGED_TIME)) -- DST
end as intH
FROM SUPPORT_DATABASE.dbo.LOG WITH (nolock))
SELECT *,COUNT(*) CT
FROM cte
GROUP BY ForDate, txtW, intW, intH
這是一種簡單的清理方式,確保它也需要重構。
您可以創建一個UDF:
CREATE FUNCTION dbo.YourFunctionName (@DateTime DATETIME)
RETURNS DATE
AS
BEGIN
RETURN
(
SELECT case
when @DateTime between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(@DateTime) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(@DateTime) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(@DateTime) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(@DateTime) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(@DateTime) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(@DateTime) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(@DateTime) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(@DateTime) as varchar(4)) as datetime)))
end
then CAST(dateadd(hh,-5,@DateTime) AS date) -- DST
else CAST(dateadd(hh,-6,@DateTime) AS date) -- DST
end
);
END
那么您的查詢就是:
SELECT dbo.YourFunctionName(LOGGED_TIME) AS ForDate,
DATENAME(WEEKDAY, dbo.YourFunctionName(LOGGED_TIME)) AS txtW
....
GROUP BY dbo.YourFunctionName(LOGGED_TIME);
或者,如果您永遠不會重復使用此功能並且不為此而創建,可以將邏輯移至APPLY,然后引用新列:
SELECT fd.ForDate,
DATENAME(WEEKDAY, fd.ForDate) AS txtW
FROM ...
CROSS APPLY
(
SELECT case
when LOGGED_TIME between
case DATEPART(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-4,CAST('03/08/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))--2am minus 6 hours for conversion from UST going to DST
else dateadd(hh,-4,DATEADD(d,15-datepart(dw,CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('03/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
and
case DATEPART(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime))
when 1 then dateadd(hh,-3,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)) --2am minus 5 hours for conversion from UST going from DST
else dateadd(hh,-3,DATEADD(d,8-datepart(dw,CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)),CAST('11/01/'+CAST (YEAR(LOGGED_TIME) as varchar(4)) as datetime)))
end
then CAST(dateadd(hh,-5,LOGGED_TIME) AS date) -- DST
else CAST(dateadd(hh,-6,LOGGED_TIME) AS date) -- DST
end as ForDate
) AS fd
GROUP BY fd.ForDate;
或最后,您可以使用子查詢,而僅在外部查詢中使用組。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.