2010-05-09 5 views
3

J'essaie d'exécuter une requête sur une table dans ma base de données SQL Server 2008. J'ai une procédure stockée qui utilise cinq paramètres int. Actuellement, mes paramètres sont définis comme suit:Clauses WHERE conditionnelles dans SQL Server 2008

@memberType int, 
@color int, 
@preference int, 
@groupNumber int, 
@departmentNumber int 

Cette procédure sera transmise -1 ou plus pour chaque paramètre. Une valeur de -1 signifie que la clause WHERE ne doit pas prendre en compte ce paramètre dans la jointure/clause. Si la valeur du paramètre est supérieure à -1, je dois considérer la valeur dans ma clause WHERE. Je préférerais NE PAS utiliser une instruction IF-ELSE parce que cela semble négligé dans ce cas.

J'ai vu cette question here. Cependant, cela n'a pas fonctionné pour moi. Je pense que la raison en est que chacune des colonnes de ma table peut avoir une valeur NULL. Quelqu'un a pointé ce scénario dans la cinquième réponse. Cela semble m'arriver.

Y a-t-il une approche délicate à ma question? Ou dois-je juste besoin de la force brutale (je l'espère :()

Merci

Répondre

4

Je l'ai fait quelque chose comme ça dans le passé.!

SELECT 
    ..... 
FROM 
    dbo.SOMETABLE AS T 
WHERE 
    (T.memberType = @memberType OR @memberType = -1) 
    AND (T.color = @color OR @color = -1) 
    AND (T.preference = @preference OR @preference = -1) 
    AND (T.groupNumber = @groupNumber OR @groupNumber = -1) 
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber = -1) 

En général, cependant, . mes paramètres que je ne se soucient pas sont NULL alors la requête devient:.

SELECT 
    ..... 
    FROM 
    dbo.SOMETABLE AS T 
    WHERE 
    (T.memberType = @memberType OR @memberType IS NULL) 
    AND (T.color = @color OR @color IS NULL) 
    AND (T.preference = @preference OR @preference IS NULL) 
    AND (T.groupNumber = @groupNumber OR @groupNumber IS NULL) 
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber IS NULL) 
+0

Est-ce plus rapide que d'utiliser 'COALESCE' (pour le cas NULL)? – crush

1

Je suggère sql dynamique - générer la requête comme une chaîne (varchar) en fonction des paramètres que vous recevez Ajouter uniquement les éléments t o la clause where dont vous avez vraiment besoin. Ensuite, utilisez sp_executesql pour l'exécuter. SQL dynamique est généralement moins efficace que SQL pré-compilé, mais dans votre cas, il semble que la bonne façon de procéder. Assurez-vous de paramétrer la requête pour optimiser l'optimiseur lors de la réutilisation des plans de requête.

+0

J'ai toujours trouvé SQL dynamique dans une procédure stockée un peu étrange. La seule fois où je l'ai utilisé, c'est dans certaines situations ouvertes. – BradBrening

+0

Je l'utilise généralement dans des choses comme les pages de recherche où l'utilisateur a beaucoup d'options de filtrage différentes. La plupart du temps, il ne s'agit pas simplement de quelques extra 'ou' dans la clause 'where' - cela peut aussi nécessiter des tables supplémentaires dans la clause 'from'. Dans ces cas, il peut être plus efficace d'utiliser SQL dynamique qu'une seule requête énorme qui tente de couvrir toutes les bases. – Ray

3

Je réalise que le thread est plus ancien, mais voici quelques détails supplémentaires qui peuvent aider à prendre une décision appropriée. Il y a plusieurs solutions:

1)

SELECT ... 
FROM ... 
WHERE 
    (T.memberType = @memberType OR @memberType = -1) 
    AND (T.color = @color OR @color = -1) 
    AND (T.preference = @preference OR @preference = -1) 
    AND (T.groupNumber = @groupNumber OR @groupNumber = -1) 
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber = -1) 

2)

SELECT ... 
FROM ... 
WHERE 
    (T.memberType = @memberType OR @memberType IS NULL) 
    AND (T.color = @color OR @color IS NULL) 
    AND (T.preference = @preference OR @preference IS NULL) 
    AND (T.groupNumber = @groupNumber OR @groupNumber IS NULL) 
    AND (T.departmentNumber = @departmentNumber OR @departmentNumber IS NULL) 

3) générer dynamiquement le DML et utiliser EXECUTE

4) génèrent Dynamiquement la DML et l'utilisation sp_executesql

Les options 1 et 2 sont à peu près la même chose ... J'aurais tendance Pour utiliser IS NULL plutôt que -1, mais comme pour la plupart des choses, cela dépend de la situation. L'un des inconvénients de ces options est que la première exécution de la procédure stockée produira un plan de requête qui sera réutilisé dans tous les appels suivants ... au fur et à mesure que les valeurs du paramètre changent (en particulier, celles que vous voulez ignorer), le plan de requête initial peut ne plus être le plan optimal ... pour contourner ce problème, utilisez l'option WITH RECOMPILE (avec la mise en garde que la procédure sera recompilée chaque fois qu'elle est appelée).

Les options 3 et 4 fonctionnent mieux lorsque plus de données sont ajoutées à la ou aux tables et/ou que plusieurs critères sont ajoutés à la clause WHERE. Cependant, ces options nécessitent plus d'efforts pour écrire la procédure stockée et requièrent plus de validation des paramètres d'entrée pour minimiser la vulnérabilité potentielle d'injection SQL.L'option 4 est meilleure que l'option 3 et est un peu plus simple dans un sens car votre SQL généré dynamiquement contient les noms des paramètres, ce qui conduit à une réutilisation du plan de requête plus efficace. Un autre inconvénient du SQL généré dynamiquement est que l'utilisateur appelant la procédure stockée doit avoir toutes les permissions nécessaires sur les tables/vues sous-jacentes ... sauf si la procédure est définie avec la clause WITH EXECUTE AS .... En fin de compte, j'utilise généralement SQL généré dynamiquement avec sp_executesql pour produire les requêtes les plus performantes.