繁体   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