2016-03-04 5 views
0

J'ai une procédure stockée avec laquelle j'essaye de travailler pour la rendre plus efficace. Malheureusement, il est actuellement potentiellement utilisé par de nombreuses applications, donc bien que ma solution optimale soit de le réécrire, je suis actuellement contraint par ce qui est là.Force un court-circuit sur une instruction CASE

Initialement, il existe deux paramètres d'entrée, tous deux VARCHAR. J'ai besoin de faire une comparaison entre les deux types de données différents en fonction de la valeur du premier paramètre. Cependant, j'obtiens des erreurs de conversion quand elles ne devraient pas exister. Exemple:

PROCEDURE ProcedureName 
     @SearchType VARCHAR(24) 
     , @SearchID VARCHAR(100) 
    AS 

    BEGIN 
     SELECT 
     t1.*, 
     t2.* 
     FROM 
     TableOne t1 
     JOIN TableTwo t2 
     WHERE 
      (CASE 
       WHEN UPPER(@SearchType) = 'GUID' THEN CAST(t2.guid AS VARCHAR(100)) 
       WHEN UPPER(@SearchType) = 'ID' THEN t2.id 
       WHEN UPPER(@SearchType) = 'ANOTHERID' THEN t1.id 
      END) 
      = 
      (CASE 
       WHEN UPPER(@SearchType) = 'GUID' THEN @SearchID 
       WHEN UPPER(@SearchType) = 'ID' 
        OR UPPER(@SearchType) ='ANOTHERID' THEN CAST(@SearchID AS INT) 
      END) 
    END 

L'objectif est ici si le type de recherche est GUID, il convertira la colonne guid dans le tableau et de faire une comparaison avec la chaîne d'entrée. Étant donné que les deux champs ID de la base de données sont des colonnes de type int, je voudrais convertir le SearchID, qui aura un type de données sous-jacent d'entier lorsque ID ou ANOTHERID sont passés, en un type entier pour correspondre au type de colonne natif. Cependant, chaque fois que j'essaie d'exécuter ceci avec GUID dans @SearchType et un guid dans @SearchID, j'obtiens cette erreur: La conversion a échoué lors de la conversion de la valeur varchar '< @SearchID>' en type de données int.

Cette déclaration de cas ne devrait-elle pas être en court-circuit, donc aucune conversion en int ne devrait jamais se produire avec cette entrée? Puis-je le forcer à court-circuiter?

+0

Supprimer tous les calculs et conversions de la clause 'where', déclarer trois variables de types appropriés, les affecter avant l'instruction' select' et utiliser prêt à comparer les variables dans 'where'. Et mettre 'option (recompiler)' 'car le plan stocké ne vous réconfortera pas lors des prochaines courses. –

+0

J'ai ajouté ce qui suit à la procédure: 'IF UPPER (@SearchType) = 'ID' OU UPPER (@SearchType) = 'ANOTHERID' BEGIN SET @IntSearchID = CAST (@SearchID AS INT) END' Je puis faites la comparaison à la fin avec une seule nouvelle variable, car la variable d'entrée est déjà un varchar, et les deux autres options sont toutes deux int: WHEN UPPER (@SearchType) = 'ID' OU UPPER (@SearchType) = 'ANOTHERID 'THEN @IntSearchID Cependant, je reçois toujours l'erreur de conversion. – Smoothjedi

Répondre

1

Le problème ne réside pas dans la comparaison entre les deux expressions CASE, mais avec chacune des expressions CASE elle-même.

CASE 
    WHEN UPPER(@SearchType) = 'GUID' THEN CAST(t2.guid AS VARCHAR(100)) 
    WHEN UPPER(@SearchType) = 'ID' THEN t2.id 
    WHEN UPPER(@SearchType) = 'ANOTHERID' THEN t1.id 
END 

Rappelez-vous que dans une expression CASE, tous les retours doivent avoir le même type de données. Si ce n'est pas le cas, ils seront convertis dans le type de données ayant la priorité la plus élevée. Dans l'expression CASE ci-dessus, vous avez un VARCHAR et deux INT. Depuis INT a une plus data type precedence, le résultat de la première WHEN est convertie en INT et une erreur est produite:

Conversion failed when converting the varchar value to data type int.

Pour résoudre ce problème, vous pouvez convertir les deux autres INT à VARCHAR:

(CASE 
    WHEN UPPER(@SearchType) = 'GUID' THEN CAST(t2.guid AS VARCHAR(100)) 
    WHEN UPPER(@SearchType) = 'ID' THEN CAST(t2.id AS VARCHAR(100)) 
    WHEN UPPER(@SearchType) = 'ANOTHERID' THEN CAST(t1.id AS VARCHAR(100)) 
END) 
= 
(CASE 
    WHEN UPPER(@SearchType) = 'GUID' THEN @SearchID 
    WHEN UPPER(@SearchType) = 'ID' 
     OR UPPER(@SearchType) ='ANOTHERID' THEN @SearchID 
END) 

Une autre option consiste à utiliser une combinaison de AND et OR conditions:

WHERE 
    (UPPER(@SearchType) = 'GUID' AND CAST(t2.guid AS VARCHAR(100)) = @SearchID) 
    OR (UPPER(@SearchType) = 'ID' AND t2.id = CAST(@SearchID AS INT)) 
    OR (UPPER(@SearchType) = 'ANOTHERID' AND t1.id = CAST(@SearchID AS INT)) 
+0

Merci pour la réponse! – Smoothjedi

+0

Je pensais que entrer me mènerait à la ligne suivante, mais à la place, il a posté heh. La première suggestion était essentiellement ce qui était déjà en place.Le souci de mon DBA était que puisque les deux tables sont assez grandes, il y a beaucoup de conversion à partir de leurs types de données natifs qui doivent se produire, ce qui peut ralentir la requête. L'objectif était de minimiser les conversions en exécutant uniquement le calcul sur la variable d'entrée. Je n'ai pas pu obtenir la deuxième suggestion pour travailler; ça m'a donné la même erreur. – Smoothjedi