web-dev-qa-db-fra.com

Sélectionnez la chaîne en tant que nombre sur Oracle

J'ai trouvé ce comportement étrange et je me casse la tête avec ça ... quelqu'un a des idées?

Oracle 10g: J'ai deux tables différentes. La colonne intitulée "TESTCOL" correspond à Varchar2 (10) , non nullable. 

Si j'exécute cette requête sur table1 , j'obtiens les résultats appropriés:

select * from table1 where TESTCOL = 1234;

Note que je ne mets pas spécifiquement '1234' ... ce n'est pas une faute de frappe, c'est une requête générée dynamique et je vais essayer de ne pas la changer (du moins pas dans un avenir proche).

Mais, si je lance la même requête, sur table2 , je reçois ce message d'erreur:

ORA-01722: Invalid number

Les deux requêtes sont exécutées sur la même session, la même base de données.

J'ai rejoint ces deux tables par cette colonne et la jointure fonctionne bien, le seul problème est que chaque fois que j'essaie d'utiliser cette condition.

Des idées sur ce qui pourrait être différent d'une table à l'autre?

Merci d'avance.

9
frenetix

Si TESTCOL contient des non-nombres, Oracle peut rencontrer des problèmes lors de la conversion des entrées TESTCOL en nombres. Parce que, ce qu'il fait en interne, c'est ceci:

select * from table1 where TO_NUMBER(TESTCOL) = 1234;

Si vous êtes tellement sûr que 1234 ne peut pas être exprimé sous la forme d'un littéral VARCHAR, essayez plutôt ceci afin de comparer les valeurs varchar plutôt que numériques:

select * from table1 where TESTCOL = TO_CHAR(1234);
25
Lukas Eder

Bien évident, TABLE2.TESTCOL contient des valeurs qui ne sont pas des nombres . La comparaison d'une chaîne à un littéral numérique génère une conversion implicite. Donc, toute valeur dans TESTCOL qui ne peut pas être convertie en un nombre lancera ORA-1722.

Cela ne vous frappe pas lorsque vous comparez les deux tables car vous comparez des chaînes.

Vous avez donc plusieurs options dont vous ne souhaiterez pas. La réponse la plus évidente consiste à nettoyer les données afin que TABLE2 ne contienne pas de données non numériques. Idéalement, vous devriez combiner cela avec le changement de la colonne en un type de données numérique. Sinon, vous pouvez modifier le générateur afin qu'il génère du code que vous pouvez exécuter sur un modèle de données shonky. Dans ce cas, cela signifie que les littéraux doivent être entourés de guillemets si la colonne mappée a un type de données caractère. 

5
APC

Vous faites face aux dangers de la conversion implicite. 

Avec l'expression testcol = 1234, vous indiquez que vous souhaitez traiter testcol comme une colonne numérique. Oracle tente donc de convertir toutes les valeurs de cette colonne en un nombre. 

ORA-01722 se produit car apparemment, au moins une valeur de cette colonne est pas un nombre. 

Même si vous prétendez que c'est "pas une faute de frappe", c'est bien une. C'est une erreur de syntaxe. 

Vous devrez déclarer votre paramètre en tant que littéral de chaîne à l'aide de guillemets simples: where testcol = '1234' 

Créer une condition correcte est la seule solution à votre problème. 

4

Ce qui suit devrait fonctionner. Il suffit de remplacer le "votre où".

select * 
from table1 
where (select TO_NUMBER(TESTCOL) 
       from table2 
       where "your where") = 1234;
0