如何不重复使用SQL where子句

时间:2018-11-19 12:12:28

标签: sql sql-server tsql datetime sql-server-2016

我有一个包含以下内容的存储过程:

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原理。

4 个答案:

答案 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”以及其他所有内容,这需要进行更改)。也就是说,这是选择“今天”或“下一个星期几”时的执行计划。在这种情况下,索引搜索基本上是您所希望的。

enter image description here