2017-08-09 67 views
0

我正在尝试合并一对几乎相同的查询,它们根据参数化变量(管道和完成)使用略有不同的WHERE子句。SQL Server:WHERE子句中的DATE或NULL变量

我很努力地找出最佳的方式来编码查找日期范围或NULL,具体取决于@ReportMode变量。

在一审WHERE条款基本上是:

DECLARE @ReportMode VARCHAR(20), 
     @ApplictnDate DATETIME; 

SET @ApplictnDate = 
    CASE 
     WHEN @ReportMode = 'Completions' THEN '20160801 00:00:00' 
     WHEN @ReportMode = 'Pipeline' THEN '20170201 00:00:00' 
    END   

SELECT 
    Id, AppDate, CompDate 
FROM 
    TbTable 
WHERE 
    AppDate > @ApplictnDate AND 
    CompDate BETWEEN '20170701 00:00:00' AND '20170731 00:00:00' 

随着第二查询中:

DECLARE @ReportMode VARCHAR(20), 
     @ApplictnDate DATETIME; 

SET @ApplictnDate = 
    CASE 
     WHEN @ReportMode = 'Completions' THEN '20160801 00:00:00' 
     WHEN @ReportMode = 'Pipeline' THEN '20170201 00:00:00' 
    END   

SELECT 
    Id, AppDate, CompDate 
FROM 
    TbTable 
WHERE 
    AppDate > @ApplictnDate AND 
    CompDate IS NULL 

问题

  1. 我能创造一个CASE声明无线使用变量细化SELECT声明或将它按@ApplictnDate需要为SET

  2. 如何在语法上创建CASE语句来处理NULL或日期范围?

感谢

+1

只需使用OR和()来将where语句保留为一个单元? – Steve

+0

只是为了挑剔:'CASE'是T-SQL中的一个**表达式**(比如'a + b') - 不是一个声明。它被评估为单一的原子价值。 –

回答

2

如果你还没有读过或重新读Sommaskogs blog post最近,它肯定是值得一读,以避免最典型的性能问题。

0

CompDate不需要CASE,您可以使用OR。

但请注意,在OR之前评估AND。
F.e. a=1 OR b=1 AND c=1评估结果为a=1 OR (b=1 AND c=1),而不是(a=1 OR b=1) AND c=1
所以包括括号以避免AND/OR陷阱。

DECLARE @ApplictnDate DATETIME = 
    CASE @ReportMode 
    WHEN 'Completions' THEN '2016-08-01' 
    WHEN 'Pipeline' THEN '2017-02-01' 
    END; 

DECLARE @CompDateStart DATETIME = '2017-07-01'; 
DECLARE @CompDateEnd DATETIME = EOMONTH(@CompDateStart); 

SELECT Id, 
     AppDate, 
     CompDate 
FROM TbTable 
WHERE AppDate > @ApplictnDate 
AND (CompDate IS NULL OR CompDate BETWEEN @CompDateStart AND @CompDateEnd); 
0

我建议对单个查询。这是可能的,但查询处理器会缓存它遇到的第一个版本,但是对于每个null和非null值可能会有更好的计划。可能你会因此而遇到性能问题。

更好的方法是针对每种情况的单独查询或过程。如果您(非常正确地)试图避免重复,则将谓词和无参数查询作为视图,然后使用不同的WHERE子句和参数应用来分隔程序/查询。