I have a table with a VARCHAR2
column which contains values that are a mixture of pure-numbers and alpha-numerics. I have a CODE
column that contains:
200
215
220
A553
D545
etc.
The following query works:
select *
from TABLE
where CLASS = 3
AND (CODE >= 210 and CODE < 220) or CODE = 291)
Values that are CLASS 3 are always numeric.
But when I add a ORDER BY
, it doesn't work:
select *
from TABLE
where CLASS = 3
and (CODE >= 210 and CODE < 220) or CODE = 291)
ORDER BY CODE
instead I get ORA-01722: invalid number
. This seems to be because the Oracle Optimiser is assessing the "order by" before the where clause, and thus non-numeric values get assessed.
I have tried changing it to ORDER BY TO_CHAR(CODE)
but to no affect. Similar negative result with trying to place it all into a sub-query.
So, how do I order the results of this query by CODE
( ASC
ending)? I guess I can specify all possible CODE
values manually in the where clause as strings (ie code = '210' or code = '211' or...
), but is there a more elegant way?
The ORDER BY
has nothing to do with the problem -- at least not directly.
SQL in general, and Oracle in particular, make no promises about the order of evaluation of conditions in the WHERE
clause. Hence, the WHERE
clause is not (necessarily) evaluated in the order written. The presence of the ORDER BY
might affect the order of evaluation of the conditions in this particular case.
In general, it is really bad practice to mix data types, the way that you are doing it. But, you can guarantee the order of evaluation by using case
:
select *
from TABLE
where CLASS = 3
'true' = (case when class <> 3 then 'false'
when (CODE >= 210 and CODE < 220) or CODE = 291) then 'true'
end);
I do not recommend doing this. I only want to point out that case
does force the order of evaluation of the conditions.
The correct solution is to use string comparisons. In this case, I would go with:
select *
from TABLE
where CLASS = 3 AND
CODE in ('210', '211', '212', '213', '214', '215', '216', '217', '218', '219', '291')
Alternatively, you could do:
where CLASS = 3 and length(CODE) = 3 and
((CODE >= '210' and CODE < '220') or CODE = '291')
Note that for accuracy you do need to take the length into account.
The problem can be in your WHERE
condition, given that it forces Oracle to cast your code to number;
Try keeping the WHERE
condition in varchar2
format:
with TABLE_(code, class_) as
(
select '200',3 from dual union all
select '215',3 from dual union all
select '220',3 from dual union all
select 'A553',3 from dual union all
select 'D545',3 from dual
)
select *
from TABLE_
where CLASS_ = 3
and ( (CODE >= '210' and CODE < '220') or CODE = '291')
ORDER BY CODE
Since the data type of code column is VARCHAR2 , you must compare it as a string in the where
clause not as a number.
Simple error reproduction :
SQL> SELECT * FROM DUAL WHERE DUMMY = 10;
SELECT * FROM DUAL WHERE DUMMY = 10
*
ERROR at line 1:
ORA-01722: invalid number
SQL>
You need to use single-quotation marks to make it a string and pass the values as IN-list rather than a range . Numeric operations on characters will use ASCII value for arithmetic.
For example,
SQL> WITH sample_data AS(
2 SELECT '210' code FROM dual UNION ALL
3 SELECT '2101' code FROM dual UNION ALL
4 SELECT '220' code FROM dual UNION ALL
5 SELECT 'A123' code FROM dual
6 )
7 --end of sample_data mimicking real table
8 SELECT code
9 FROM sample_data
10 WHERE code IN ('210', '220')
11 ORDER BY code;
CODE
----
210
220
SQL>
Now coming to the ORDERING of rows as number and not string , you must use TO_NUMBER in the SELECT
and use the same alias in the ORDER BY
clause.
For example,
SQL> WITH sample_data AS(
2 SELECT '210' code FROM dual UNION ALL
3 SELECT '2101' code FROM dual UNION ALL
4 SELECT '220' code FROM dual UNION ALL
5 SELECT 'A123' code FROM dual
6 )
7 --end of sample_data mimicking real table
8 SELECT to_number(code) code_num
9 FROM sample_data
10 WHERE code IN ('210', '220')
11 ORDER BY code_num;
CODE_NUM
----------
210
220
SELECT *
FROM table_name
WHERE class = 3
AND ( ( code >= '210' AND code < '220' AND LENGTH( code ) = 3 )
OR code = '291' )
ORDER BY CODE;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.