我有一个可以运行的SQL Server SQL语句,但它看起来很混乱且效率低下。它会检查每行数据的数据,并将其分为Yesterday
,WeektoDate
,MonthtoDate
和YeartoDate
,并按组对每个字段求和。有更好的方法吗?
以下是我所拥有的示例,实际查询中实际上有15个左右的字段,这会产生一个很长的SELECT
查询,有没有更好的方法来执行此操作?
SELECT
sum(CASE when row_date BETWEEN @YesterdayMorning and @EndOfYesterday THEN Total_Calls ELSE 0 END) AS Calls_Yesterday
,sum(CASE when row_date BETWEEN @YesterdayMorning AND @EndOfYesterday THEN Total_Time ELSE 0 END) AS Time_Yesterday
,sum(CASE when row_date BETWEEN @WTDMorning and @EndOfYesterday THEN Total_Calls ELSE 0 END) AS Calls_WTD
,sum(CASE when row_date BETWEEN @WTDMorning AND @EndOfYesterday THEN Total_Time ELSE 0 END) AS Time_WTD
,sum(CASE when row_date BETWEEN @MTDMorning and @EndOfYesterday THEN Total_Calls ELSE 0 END) AS Calls_MTD
,sum(CASE when row_date BETWEEN @MTDMorning AND @EndOfYesterday THEN Total_Time ELSE 0 END) AS Time_MTD
,sum(CASE when row_date BETWEEN @YTDMorning and @EndOfYesterday THEN Total_Calls ELSE 0 END) AS Calls_YTD
,sum(CASE when row_date BETWEEN @YTDMorning AND @EndOfYesterday THEN Total_Time ELSE 0 END) AS Time_YTD
FROM TableName
答案 0 :(得分:0)
一种选择是摆脱CASE
,将它们分成多个SELECT
个WHERE
条件的查询,然后将它们联合起来:
SELECT
'Yesterday' AS Range
SUM(Total_Calls) AS Calls,
SUM(Total_Time) AS Time
FROM TableName
WHERE row_date BETWEEN @YesterdayMorning AND @EndOfYesterday
UNION
SELECT
'WTD' AS Range,
SUM(Total_Calls) AS Calls,
SUM(Total_Time) AS Time
FROM TableName
WHERE row_date BETWEEN @WTDMorning AND @EndOfYesterday
UNION
SELECT
'MTD' AS Range,
SUM(Total_Calls) AS Calls,
SUM(Total_Time) AS Time
FROM TableName
WHERE row_date BETWEEN @MTDMorning AND @EndOfYesterday
UNION
SELECT
'YTD' AS Range,
SUM(Total_Calls) AS Calls,
SUM(Total_Time) AS Time
FROM TableName
WHERE row_date BETWEEN @YTDMorning AND @EndOfYesterday
答案 1 :(得分:0)
我不认为您的查询效率低,查询计划看起来不错,但我同意代码有点混乱。我会考虑这样的事情来避免重复的代码:
<强>查询:强>
DECLARE @day VARCHAR(2) = FORMAT(DAY(GETDATE()), '00'), @month VARCHAR(2) = FORMAT(MONTH(GETDATE()), '00'), @year INT = YEAR(GETDATE());
DECLARE @weekday INT = DATEPART(dw, GETDATE());
DECLARE @morningTime TIME = '08:00';
DECLARE @EndOfYesterday DATETIME2 = DATEADD(dd, -1, CONVERT(DATETIME2, CONCAT(YEAR(GETDATE()), MONTH(GETDATE()), DAY(GETDATE()), ' 18:00')));
DECLARE @timeTable TABLE(ID INT IDENTITY(1,1) PRIMARY KEY, Name VARCHAR(255), FromDate DATETIME2);
INSERT INTO @timeTable
SELECT 'Yesterday', DATEADD(dd, -1, CONVERT(DATETIME2, CONCAT(@year, @month, @day, ' ', @morningTime)))
UNION ALL SELECT 'WTDMorning', DATEADD(dd, -(@weekday-1), CONVERT(DATETIME2, CONCAT(@year, @month, @day, ' ', @morningTime)))
UNION ALL SELECT 'MTDMorning', CONVERT(DATETIME2, CONCAT(@year, @month, '01', ' ', @morningTime))
UNION ALL SELECT 'YTDMorning', CONVERT(DATETIME2, CONCAT(@year, '01', '01', ' ', @morningTime))
SELECT t.Name, Total_Calls = SUM(c.Total_Calls), Total_Time = SUM(c.Total_Time)
FROM @timeTable t
LEFT JOIN TableName c ON c.row_date BETWEEN t.FromDate AND @EndOfYesterday
GROUP BY ID, t.Name
ORDER BY ID
在我的测试数据中,您的查询实际上比我的查询的查询成本低15%,但在“调用表”上的索引比我的查询便宜20%。
索引:
CREATE NONCLUSTERED INDEX idxRowDate
ON [dbo].[TableName] ([row_date])
INCLUDE ([Total_Calls],[Total_Time])
我知道这与您的输出100%不匹配,但我相信行比15列更容易使用。如果需要,也可以将其转换为一行。
一行支持:
如果需要,可以使用动态sql将行转换为一行。但它变得有点复杂:
DECLARE @onRowconverter VARCHAR(MAX) = '';
SELECT @onRowconverter = @onRowconverter + CASE WHEN @onRowconverter > '' THEN ', ' ELSE 'SELECT ' END + CONCAT('[Calls_' + t.Name + '] = ', SUM(c.Total_Calls), ', [Time_' + t.Name + '] = ', SUM(c.Total_Time))
FROM @timeTable t
LEFT JOIN TableName c ON c.row_date BETWEEN t.FromDate AND @EndOfYesterday
GROUP BY ID, t.Name
ORDER BY ID
EXEC(@onRowconverter);