簡體   English   中英

Oracle使用混合varchar列但使用數字where子句對結果進行排序

[英]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)但沒有任何影響。 嘗試將所有內容都放入子查詢中的結果類似。

那么,如何按CODEASC結尾)排序此查詢的結果? 我想我可以在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM