[英]Oracle ordering of results using a mixed varchar column but numeric where clause
我有一個帶有VARCHAR2
列的表,該列包含純數字和字母數字的混合值。 我有一個CODE
列,其中包含:
200
215
220
A553
D545
etc.
以下查詢有效:
select *
from TABLE
where CLASS = 3
AND (CODE >= 210 and CODE < 220) or CODE = 291)
CLASS 3的值始終是數字。
但是當我添加ORDER BY
,它不起作用:
select *
from TABLE
where CLASS = 3
and (CODE >= 210 and CODE < 220) or CODE = 291)
ORDER BY CODE
相反,我得到ORA-01722: invalid number
。 這似乎是因為Oracle Optimiser正在評估where子句之前的“ order by”,因此會評估非數字值。
我嘗試將其更改為ORDER BY TO_CHAR(CODE)
但沒有任何影響。 嘗試將所有內容都放入子查詢中的結果類似。
那么,如何按CODE
( ASC
結尾)排序此查詢的結果? 我想我可以在where子句中手動將所有可能的CODE
值指定為字符串(即code = '210' or code = '211' or...
),但是還有一種更優雅的方法嗎?
ORDER BY
與問題無關-至少不是直接相關。
通常,SQL(尤其是Oracle)對WHERE
子句中條件的評估順序不做任何保證。 因此, WHERE
子句不會(必須)按照編寫的順序求值。 在這種特殊情況下, ORDER BY
的存在可能會影響條件評估的順序。
通常,將數據類型混合在一起是一種非常不好的做法。 但是,您可以使用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);
我不建議這樣做。 我只想指出,這種case
確實會強制評估條件。
正確的解決方案是使用字符串比較。 在這種情況下,我可以選擇:
select *
from TABLE
where CLASS = 3 AND
CODE in ('210', '211', '212', '213', '214', '215', '216', '217', '218', '219', '291')
或者,您可以執行以下操作:
where CLASS = 3 and length(CODE) = 3 and
((CODE >= '210' and CODE < '220') or CODE = '291')
請注意,為確保准確性,您確實需要考慮長度。
問題可能出在您的WHERE
狀態,因為它迫使Oracle將代碼強制轉換為數字。
嘗試將WHERE
條件保持為varchar2
格式:
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
由於代碼列的數據類型為VARCHAR2 ,因此必須在where
子句中將它作為字符串進行比較,而不是數字。
簡單的錯誤再現 :
SQL> SELECT * FROM DUAL WHERE DUMMY = 10;
SELECT * FROM DUAL WHERE DUMMY = 10
*
ERROR at line 1:
ORA-01722: invalid number
SQL>
您需要使用單引號將其設置為字符串,並將值作為IN-list而不是range傳遞。 對字符的數字運算將使用ASCII值進行算術運算。
例如,
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>
現在來行作為數而不是串的順序 ,你必須在使用TO_NUMBER SELECT
,並使用相同的別名在ORDER BY
子句。
例如,
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.