Reputation: 1708
I have a view from some tables:
SELECT UM00200M.ACCOUNT_NO AS INDEX1,
CONCAT (CONCAT (TRIM (UM00200M.PERSON_LNM), ' '),
TRIM (UM00200M.PERSON_FNM))
AS INDEX2,
DECODE (NVL (TRIM (SG00100M.PERSON_ID_CUSTOM), 0),
0, UM00200M.PERSON_NO,
SG00100M.PERSON_ID_CUSTOM)
INDEX3,
NULL AS INDEX4,
'CONS_ACCTG' AS GROUPNAME
FROM UM00200M, SG00100M
WHERE UM00200M.PERSON_NO = SG00100M.PERSON_NO
Which gives me (Sorry for the formatting):
Column_Name DATA_TYPE NULLABLE COLUMNT_ID COMMENTS INSERTABLE UPDATEABLE INDEX1 NUMBER(14,0) No 1 YES YES YES INDEX2 VARCHAR2(81) Yes 2 NO NO NO INDEX3 NUMBER Yes 3 NO NO NO INDEX4 VARCHAR2(0) Yes 4 NO NO NO GROUPNAME CHAR(10) Yes 5 NO NO NO
I am looking for all the records that have INDEX3 = 524118914
--Looking for INDEX3 = 524118914
--Fails: 01722. 00000 - "invalid number"
Select *
from Cayenta.CAHeader
where INDEX3 = 524118914;
--Fails: 01722. 00000 - "invalid number"
Select *
from Cayenta.CAHeader
where INDEX3 > 524118000 and INDEX3 < 524118999;
--Works
Select *
from Cayenta.CAHeader
where INDEX3 > 524118000 and INDEX3 < 524999999;
--Fails: 01722. 00000 - "invalid number"
Select *
from Cayenta.CAHeader
where INDEX3 > 524118000 and INDEX3 < 524999999
ORDER BY INDEX3;
I don't get the results that I expect when I execute the query. Why would I get "invalid number?"
I thought it would be something to do with the DECODE function, and SG00100M.PERSON_ID_CUSTOM is a CHAR(15 BYTE) field, but filled with all numeric data. (I know - bad design, but it's a 3rd-party product.)
I appreciate any insights anyone can offer.
Upvotes: 0
Views: 144
Reputation: 2895
What's happening here is implicit conversion. This means that in the condition in the where clause, you are comparing the column INDEX3 with a number.
INDEX3 is a CHAR column so the following excerpt from the Oracle document applied with respect to implicit conversion:
During arithmetic operations on and comparisons between character and noncharacter datatypes, Oracle converts from any character datatype to a numeric, date, or rowid, as appropriate
This means that all the values from INDEX3 will be converted to a NUMBER in order to allow them to be compared to the number that you have given in the example.
The simple way to get around this is to use quotes around the number and treat it as a character string.
where INDEX3 = '524118914'
This will work for the equality condition but may not work so well for the ranges using >= and <= unless they are padded with zeroes at the beginning. Using the correct data types also means that any indexes on this column will be used.
If you think that this should be a number field, then there is at least one row that has nonnumeric data in it. To track this down you could try checking the data by using the following condition:
where regexp_like(INDEX3, '[^[:digit:]]')
This only checks for numbers (not decimal points etc) so you may need to tailor it to your requirements.
I was a little confused about why the database was saying that the column has a numeric data type. It seems that this is related to the way that the DECODE statement is evaluated and the data type comes from the first result argument, even though the default argument is a CHAR type.
Upvotes: 1
Reputation: 565
Storing Numbers in Character-Fields is always a pain...
Please try the following SQL for the View - The decodes checks PERSON_ID_CUSTOM for a Number. If it is, in converts it, if not - it'll be replaced by NULL:
SELECT UM00200M.ACCOUNT_NO AS INDEX1,
CONCAT (CONCAT (TRIM (UM00200M.PERSON_LNM), ' '),
TRIM (UM00200M.PERSON_FNM))
AS INDEX2,
DECODE (NVL (TRIM (SG00100M.PERSON_ID_CUSTOM), 0),
0, UM00200M.PERSON_NO,
decode((
REPLACE(
TRANSLATE(
TRIM(SG00100M.PERSON_ID_CUSTOM),'0123456789','00000000000'
),'0' ,NULL
)
),NULL,to_number(trim(SG00100M.PERSON_ID_CUSTOM)))
) INDEX3,
NULL AS INDEX4,
'CONS_ACCTG' AS GROUPNAME
FROM UM00200M, SG00100M
WHERE UM00200M.PERSON_NO = SG00100M.PERSON_NO
Upvotes: 0