web-dev-qa-db-fra.com

Clause WHERE conditionnelle dans SQL Server

Je crée une requête SQL dans laquelle j'ai besoin d'une clause where conditionnelle. 

Cela devrait être quelque chose comme ça:

SELECT 
    DateAppr,
    TimeAppr,
    TAT,
    LaserLTR,
    Permit,
    LtrPrinter,
    JobName,
    JobNumber,
    JobDesc,
    ActQty,
    (ActQty-LtrPrinted) AS L,
    (ActQty-QtyInserted) AS M,
    ((ActQty-LtrPrinted)-(ActQty-QtyInserted)) AS N
FROM 
    [test].[dbo].[MM]
WHERE 
    DateDropped = 0
            --This is where i need the conditional clause 
    AND CASE
            WHEN @JobsOnHold = 1 THEN DateAppr >=  0
            ELSE  DateAppr != 0
        END

La requête ci-dessus ne fonctionne pas. N'est-ce pas la syntaxe correcte ou existe-t-il une autre façon de faire que je ne connais pas? 

Je ne souhaite pas utiliser le SQL dynamique. Y a-t-il un autre moyen ou dois-je utiliser une solution de contournement comme utiliser if else et utiliser la même requête avec différentes clauses where?

49
user2721874

Essaye ça 

SELECT 
    DateAppr,
    TimeAppr,
    TAT,
    LaserLTR,
    Permit,
    LtrPrinter,
    JobName,
    JobNumber,
    JobDesc,
    ActQty,
    (ActQty-LtrPrinted) AS L,
    (ActQty-QtyInserted) AS M,
    ((ActQty-LtrPrinted)-(ActQty-QtyInserted)) AS N
FROM 
    [test].[dbo].[MM]
WHERE 
    DateDropped = 0
    AND (
    (ISNULL(@JobsOnHold, 0) = 1 AND DateAppr >= 0) 
    OR 
    (ISNULL(@JobsOnHold, 0) != 1 AND DateAppr != 0)
    )

Vous pouvez en savoir plus sur conditionnel OERE ici.

65
Coder of Code

Essaye celui-là -

WHERE DateDropped = 0
    AND (
        (ISNULL(@JobsOnHold, 0) = 1 AND DateAppr >= 0) 
        OR 
        (ISNULL(@JobsOnHold, 0) != 1 AND DateAppr != 0)
    )
23
Devart

Pour répondre à la question sous-jacente de l’utilisation d’une expression CASE dans la clause WHERE: 

Rappelez-vous tout d'abord que la valeur d'une expression CASE doit avoir une valeur de type de données normale et non une valeur booléenne. Ce doit être un varchar, ou un int, ou quelque chose. C'est la même raison pour laquelle vous ne pouvez pas dire SELECT Name, 76 = Age FROM [...] et vous attendre à obtenir 'Frank', FALSE dans l'ensemble de résultats.

De plus, toutes les expressions d'une clause WHERE doivent avoir une valeur booléenne. Ils ne peuvent pas ont la valeur varchar ou int. Vous ne pouvez pas dire WHERE Name; ou WHERE 'Frank';. Vous devez utiliser un opérateur de comparaison pour en faire une expression booléenne, donc WHERE Name = 'Frank';

Cela signifie que l'expression CASE doit être d'un côté d'une expression booléenne. Vous devez comparer l'expression CASE à quelque chose. Il ne peut pas rester seul!

Ici:

WHERE 
    DateDropped = 0
    AND CASE
            WHEN @JobsOnHold  = 1 AND DateAppr >= 0 THEN 'True'
            WHEN DateAppr != 0 THEN 'True'
            ELSE 'False'
        END = 'True'

Notez qu'à la fin, l'expression CASE à gauche transformera l'expression booléenne en 'True' = 'True' ou 'False' = 'True'.

Notez qu'il n'y a rien de spécial à propos de 'False' et 'True'. Vous pouvez aussi utiliser 0 et 1 si vous préférez.

Vous pouvez généralement réécrire l'expression CASE en expressions booléennes avec lesquelles nous sommes plus familiers, ce qui améliore généralement les performances. Cependant, il est parfois plus facile ou plus facile à gérer d'utiliser une expression existante que de convertir la logique.

9
Bacon Bits

Le problème de votre requête est que, dans les expressions CASE, les parties THEN et ELSE doivent avoir une expression dont le résultat est un nombre, un varchar ou tout autre type de données, mais pas une valeur booléenne.

Vous devez juste utiliser la logique booléenne (ou plutôt la logique ternaire utilisée par SQL) et la réécrire:

WHERE 
    DateDropped = 0
AND ( @JobsOnHold = 1 AND DateAppr >= 0 
   OR (@JobsOnHold <> 1 OR @JobsOnHold IS NULL) AND DateAppr <> 0
    )
7
ypercubeᵀᴹ

Souvent, lorsque vous utilisez des clauses WHERE conditionnelles, vous vous retrouvez avec une requête extrêmement inefficace, ce qui est perceptible pour les grands ensembles de données où des index sont utilisés. Un excellent moyen de optimiser la requête pour différentes valeurs de votre paramètre consiste à créer un plan d’exécution différent pour chaque valeur du paramètre. Vous pouvez y parvenir en utilisant OPTION (RECOMPILE).

Dans cet exemple, cela ne ferait probablement pas beaucoup de différence, mais que la condition ne devrait être utilisée que dans l'un des deux cas, vous pourriez alors constater un impact important.

Dans cet exemple:

WHERE 
    DateDropped = 0
    AND (
    (ISNULL(@JobsOnHold, 0) = 1 AND DateAppr >= 0) 
    OR 
    (ISNULL(@JobsOnHold, 0) <> 1 AND DateAppr <> 0)
    )
OPTION (RECOMPILE)

Source Recherche de paramètres, incorporation, et options RECOMPILE

0
wezzix