2017-08-09 3 views
0

Je suis en train de tenter d'amalgamer une paire de requêtes presque identiques, qui utilisent des clauses WHERE légèrement différentes en fonction des variables paramétrées (Pipeline et Completions).SQL Server: DATE ou NULL Variable dans la clause WHERE

J'ai du mal à trouver la meilleure façon de le coder pour chercher une plage de dates ou une valeur NULL en fonction de la variable @ReportMode.

La clause WHERE en première instance est essentiellement:

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' 

Avec la seconde étant de requête:

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 

Questions:

  1. Puis-je créer un CASE déclaration wi affiner l'instruction SELECT en utilisant la variable ou devra-t-elle être SET selon @ApplictnDate? Comment créer l'instruction CASE de manière syntaxique pour traiter une plage de dates NULL ou une plage de dates?

Merci

+1

Utilisez simplement un OR et() pour conserver les instructions where comme une seule unité? – Steve

+0

Juste pour être nitpicky: 'CASE' est une ** expression ** (comme' a + b') dans T-SQL - pas une déclaration. C'est quelque chose qui est évalué à une seule valeur atomique. –

Répondre

2

Si vous avez pas lu ou relus Sommaskogs blog post récemment, il est très certainement la peine de lire, pour éviter les problèmes de performance les plus typiques.

0

Un CAS n'est pas nécessaire pour CompDate, vous pouvez utiliser un OU.

Mais sachez que ET est évalué avant un OU.
F.e. a=1 OR b=1 AND c=1 évalue comme a=1 OR (b=1 AND c=1), pas (a=1 OR b=1) AND c=1
Donc incluez les parenthèses pour éviter l'écueil ET/OU.

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

Je conseille contre une seule requête. C'est possible mais le processeur de requête mettra en cache la première version qu'il rencontre mais il y aura probablement de meilleurs plans pour chacune des valeurs nulles et non nulles. Vous allez probablement rencontrer des problèmes de performance.

Une meilleure approche serait des requêtes séparées ou des procédures pour chaque cas. Si vous essayez (à juste titre) d'éviter la répétition, faites la requête sans prédicat et sans paramètre en tant que vue, puis séparez les procédures/requêtes avec différentes clauses WHERE et l'application des paramètres.