簡體   English   中英

sum(否則結束的情況)語句

[英]sum (case when else end) statement

我有一個可以運行的SQL Server SQL語句,但是它看起來很雜亂且效率低下。 它檢查每一行數據以獲取其數據,並將其分組為YesterdayWeektoDateMonthtoDateYeartoDateMonthtoDate組對每個字段求和。 有一個更好的方法嗎?

以下是我所擁有的示例,實際查詢中實際上有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

一種選擇是擺脫CASE ,將它們分解為具有WHERE條件的多個SELECT查詢,然后將它們合並:

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

我認為您的查詢效率不高,查詢計划看起來還可以,但是我同意代碼有點混亂。 我會考慮這樣的事情,以避免重復的代碼:

  • 將所有早晨日期添加到表中
  • 將日期加入通話表
  • 通話總和和通話時間

查詢:

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM