我有一个包含以下内容的存储过程:
declare @dueTypeCode nvarchar(3) = 'ALL' --Is actually a parameter that is passed into the stored procedure
declare @today DateTime = GetUtcDate();
declare @tomorrow DateTime = dateadd(day,datediff(day,-1,GETUTCDATE()),0);
declare @fiveDaysFromNow DateTime = dateadd(day,datediff(day,-5,GETUTCDATE()),0);
if(@dueTypeCode = 'ALL')
Select * from Items
ELSE IF (@dueTypeCode = 'TODAY')
Select * from Items where DueDate = @today
ELSE IF (@dueTypeCode = 'NEXT5DAYS')
Select * from Items where DueDate >= @today and DueDate <= @fiveDaysFromNow
END
有什么方法可以将其包装到单个SQL语句中,以避免重复上面的代码?
实际的select语句要复杂得多,重复3次只是为了更改where子句似乎违反了DRY原理。
答案 0 :(得分:4)
您可以这样做:
select i.*
from Items i
where (@dueTypeCode = 'ALL') or
(@dueTypeCode = 'TODAY' and DueDate = @today) or
(@dueTypeCode = 'NEXT5DAYS' and DueDate >= @today and DueDate <= @fiveDaysFromNow);
不利之处在于,如果索引可以用于该查询(尤其是在DueDate
上),则这样做的效率可能不如原始查询。
答案 1 :(得分:1)
由于您正在使用变量,为什么不修改变量:
DECLARE @dueTypeCode NVARCHAR(10) = 'NEXT5DAYS';
DECLARE @date1 DATE = NULL;
DECLARE @date2 DATE = NULL;
IF @dueTypeCode = 'TODAY'
BEGIN
SET @date1 = GETUTCDATE();
SET @date2 = GETUTCDATE() + 1;
END
ELSE IF @dueTypeCode = 'NEXT5DAYS'
BEGIN
SET @date1 = GETUTCDATE();
SET @date2 = GETUTCDATE() + 6;
END
SELECT * FROM Items
WHERE (@date1 IS NULL OR DueDate >= @date1)
AND (@date2 IS NULL OR DueDate < @date2)
答案 2 :(得分:1)
我的风格:
declare @dueTypeCode nvarchar(3) = 'ALL' --Is actually a parameter that is passed
into the stored procedure
declare @today DateTime = GetUtcDate();
declare @tomorrow DateTime = dateadd(day,datediff(day,-1,GETUTCDATE()),0);
declare @fiveDaysFromNow DateTime = dateadd(day,datediff(day,-5,GETUTCDATE()),0);
Select *
from Items
where 1= case @dueTypeCode
when 'ALL' then 1
when 'TODAY' then
case when DueDate = @today then 1 else 0 end
when 'NEXT5DAYS' then
case when DueDate >= @today and DueDate <= @fiveDaysFromNow then 1 else 0 end
else
0
end
答案 3 :(得分:0)
以Gordon发布的内容为基础-使用Dynamic SQL可以获得最佳性能。从此示例数据开始:
SET NOCOUNT ON;
USE tempdb;
GO
IF OBJECT_ID('dbo.items','U') IS NOT NULL DROP TABLE dbo.items;
GO
SELECT col1 = CAST(NEWID() AS VARCHAR(100)),
DueDate = ISNULL(DATEADD(DAY,t.c*2,d.dt),d.dt)
INTO dbo.items
FROM (VALUES(0),(0),(1),(2),(3),(4)) AS t(c)
CROSS JOIN (VALUES(CAST(GETDATE() AS DATE))) AS d(dt);
GO
CREATE CLUSTERED INDEX cl_nu__dbo_items__DueDate ON dbo.items(DueDate);
GO
解决方案:
DECLARE @dueTypeCode VARCHAR(100) = 'TODAY' --'NEXT5DAYS --'ALL';
DECLARE @sql NVARCHAR(4000) =
N'SELECT i.*
FROM dbo.Items i'+CHAR(10);
SELECT @sql +=
CASE @dueTypeCode
WHEN 'TODAY' THEN 'WHERE DueDate = CAST(getdate() AS date);'
WHEN 'NEXT5DAYS' THEN 'WHERE DueDate >= CAST(getdate() AS date) AND DueDate <= DATEADD(DAY,5,CAST(getdate() AS date))'
ELSE ''
END;
EXEC sp_executesql @statement = @sql;
显然,业务逻辑需要进行更新以满足您的需求(例如,请注意我懒惰地使用ELSE ''
处理“ ALL”以及其他所有内容,这需要进行更改)。也就是说,这是选择“今天”或“下一个星期几”时的执行计划。在这种情况下,索引搜索基本上是您所希望的。