La fonction Cast échoue à partir de la table dérivée SQL Server 2008

J'ai une table avec des codes alphanumériques. Dans ce cas particulier, je ne suis pas concerné par les codes qui sont de nature alphanumérique, seulement ceux qui contiennent des nombres entiers. J'ai écrit une petite requête pour find le sous-set de codes dont j'avais besoin:

select CAST(icd as float) as icd from ( select i.icd from icd as i where icd like '952%' or icd like '806%' or icd like '3440%' or icd like '3441' )t 

Cela me renvoie une list des codes dont j'avais besoin. Cependant, lorsque j'essaie d'utiliser une clause where comme:

where icd between 80600 and 80610 la requête échoue, me disant qu'il ne peut pas convertir le type de données varchar en int. Cependant, si je fais quelque chose comme

 select CAST(icd as float) as icd,icd+10 from ( select i.icd from icd as i where icd like '952%' or icd like '806%' or icd like '3440%' or icd like '3441' )t 

Je peux append dix à chaque code et il s'exécute, ce qui signifie qu'ils sont en fait des entiers. Je veux utiliser la clause where comme ceci parce que les codes 80600-80610 devraient être étiquetés X et 80611-80620 ils devraient être étiquetés Y. Je peux le faire manuellement pour chaque code, mais j'aimerais être plus extensible que cela.

Comment puis-je m'assurer que SQL Server ne regarde la table dérivée qu'en utilisant cette clause where, au lieu d'échouer?

Les filters sont exécutés avant que les résultats ne soient affichés

Ce que vous faites est de couler des résultats pas des valeurs de colonne lorsque la requête s'exécute (et fait tout le filtrage). Les filters ( where clause) sont évalués avant que les valeurs de résultat ne soient castées.

Pour continuer à travailler avec le même set de résultats que celui que vous montrez dans votre exemple, le plus simple est d'utiliser un CTE au lieu d'une sous-requête, puis d'effectuer un filtrage supplémentaire sur celui-ci:

 with codes as ( select cast(icd as int) as icd from icd where icd like '952%' or icd like '806%' or icd like '3440%' or icd like '3441' ) select icd, 'X' as label from codes where icd between 80600 and 80610 union all select icd, 'Y' from codes where icd between 80611 and 80620 

Que les CTE soient plus / less lisibles que les sous-requêtes est une question de discussion / d'arguments sans fin. Mais dans ce cas où nous réutilisons la même expression de table pour get des résultats étiquetés X et Y, elle utilise less de code par rapport à ce qui serait nécessaire pour faire la même chose avec des sous-requêtes. Dans ce cas, il est de loin plus lisible.

Les données à lancer doivent être numériques bien sûr

Lorsque vous lancez des données, vous devez vous assurer qu'il peut réellement être converti en type de résultat. Si votre valeur est 064 V il est clair que ce n'est pas un nombre qui ne peut donc pas être lancé. un appel à isnumeric peut aider ici:

 with codes as ( select cast(icd as int) as icd from icd where isnumeric(icd) = 1 and ( icd like '952%' or icd like '806%' or icd like '3440%' or icd like '3441' ) ) select icd, 'X' as label from codes where icd between 80600 and 80610 union all select icd, 'Y' from codes where icd between 80611 and 80620 

votre requête interne renvoie probablement des champs varchar. Peux-tu courrir

 select i.icd from icd as i where icd like '952%' or icd like '806%' or icd like '3440%' or icd like '3441' 

et assurez-vous qu'aucune donnée de string n'est returnnée?

Pour info, puisque vous utilisez une requête interne, vous pouvez append

 WHERE IsNumeric(t.icd ) = 1 

pour être sûr que seuls les entiers sont returnnés

Vous devez vous assurer que votre filter traite ICD comme une string (ce qui est le cas), puis filter uniquement les DAI qui sont convertibles en numérique.

Il est important de noter que les comparaisons de strings doivent prendre en count la 'longueur' de votre numéro (par exemple '8061' se situe entre '80600' et '80610'), mais heureusement, il semble que votre filter se trouve dans une plage la longueur est constante.

par exemple

 where icd between '80600' and '80610' -- ie exclude '12345' and 'Apple' and length(icd) = 5 -- ie exclude '8061' and '806000001' and isnumeric(icd) = 1 -- ie exclude '8060A'