使用UNION Select中的不同数据类型进行CAST

时间:2014-09-11 09:47:00

标签: sql oracle plsql

我正在使用具有不同数据类型的UNION语句,并希望对它们进行排序。

SELECT * FROM
   (SELECT name, 'P' as 'type', to_char(order_number) as order_type FROM abc

   UNION ALL

   SELECT name, 'T' as 'type', to_char(name) as order_type FROM def
   )
ORDER BY
CASE type 
  WHEN 'P' THEN order_type
ELSE 
  order_type 
END

到目前为止这是有效的。

现在表abc中order_type的内容是整数,表def中的内容是varchar。 这就是为什么结果的顺序是错误的。 (例如1000在11之前)

我尝试使用

ORDER BY
CASE type WHEN 'P' THEN CAST(order_type AS NUMBER)
ELSE order_type END

在订单部分,但我正在

INCONSISTENT DATATYPES

我做错了什么?

表格内容:

abc

name          | order_number
'Example 1'   | 10001
'Example 2'   | 11

def

name   | order_number
'Example 4' | 0
'Example 3'  | 0

预期结果:

Example 2
Example 1
Example 3
Example 4

4 个答案:

答案 0 :(得分:1)

您的列ORDER_TYPE是一个字符串,将作为一个字符串排序,因此11在2.之前。您希望将来自表ABC的字符串作为数字排序,并按字母顺序排列来自表DEF的字符串。

一种方法可能是:

ORDER BY CASE type WHEN 'P' THEN lpad(order_type,20,'0') ELSE order_type END

那个顺序依次是字符串排序,但是用零填充数字,这将按数字排序(因为你说它是整数数据 - 如果你有一些可能使它复杂化的分数;-)

答案 1 :(得分:1)

在顺序中使用常量'4'4没有达到任何效果;不会转换为列位置。

无论原始数据类型是什么,联合都会将来自两个分支的数据呈现为相同类型(由第一个分支确定)。你有to_char(c)这意味着order_type是一个字符串; f已经是一个字符串,但即使它是一个数字,它也会被隐式转换为匹配。

CASE type WHEN 'P' THEN CAST(order_type AS NUMBER)
ELSE order_type END

当你这样做时,order_type是一个字符串; then将其转换为数字,else不是,因此数据类型不同。

如果您想以数字方式订购,请将order_type设为数字,然后按顺序排序:

SELECT * FROM
   (SELECT a,b,'P' as "type", c as order_type FROM abc
   UNION ALL
   SELECT d,e,'T' as "type", to_number(f) as order_type FROM def
   )
ORDER BY order_type;

或者如果您需要将结果集中的order_type作为字符串,请在order-by子句中将其转换回来:

SELECT * FROM
   (SELECT a,b,'P' as "type", to_char(c) as order_type FROM abc
   UNION ALL
   SELECT d,e,'T' as "type", f as order_type FROM def
   )
ORDER BY to_number(order_type);

......但这似乎相当多余。

当然,这假设f中的所有值实际上都是存储为字符串的有效数字(这是一个完全不同的主题)。如果它们不能全部被转换,那么无论哪种方式,你都会得到无效数字错误;然后你最好的选择可能是填充字符串结果@KimBergHansen建议,虽然他说非整数值可能会给出奇怪的结果,你需要选择一个适当大的长度。


根据您的问题编辑,您似乎希望首先按abc排序order_num值,然后按def排序name值。在这种情况下,使用多个元素:

SELECT * FROM
   (SELECT name, 'P' as order_type, order_num FROM abc
   UNION ALL
   SELECT name,'T' as order_type, null as order_num FROM def
   )
ORDER BY CASE WHEN order_type = 'P' THEN 1 ELSE 2 END,
  order_num,
  name;

NAME       ORDER_TYPE  ORDER_NUM
---------- ---------- ----------
Example 2  P                  11 
Example 1  P               10001 
Example 3  T                     
Example 4  T                     
来自您的样本数据的

SQL Fiddle

答案 2 :(得分:1)

重点是,在您的order by子句中,您正在混合数据类型

with t1(text) as (
  select '1' from dual union all
  select 'P' from dual union all
  select '4' from dual
  )
select * from t1
ORDER BY
CASE text 
  WHEN 'P' THEN CAST('4' AS NUMBER)
ELSE 
  '4'
END;

错误:ORA-00932: inconsistent datatypes: expected NUMBER got CHAR

这里,char与数字混合。要获得从案例返回的一致数据类型,您需要将else部分转换为数字,从案例的每个条件返回,就数据类型而言是一致的

with t1(text) as (
  select '1' from dual union all
  select 'P' from dual union all
  select '4' from dual
  )
select * from t1
ORDER BY
CASE text 
  WHEN 'P' THEN CAST('4' AS NUMBER)
ELSE 
  CAST('4' AS NUMBER) -- or just 4 without qoutes
END;

输出:

| TEXT |
|------|
|    1 |
|    4 |
|    P |

答案 3 :(得分:1)

SQL> WITH DATA AS(
  2  select ename, to_char(sal) sal from emp)
  3  select ename ,sal  from data
  4  ORDER BY
  5  to_number(sal)
  6  /

ENAME      SAL
---------- ----------------------------------
SMITH      800
JAMES      950
ADAMS      1100
WARD       1250
MARTIN     1250
MILLER     1300
TURNER     1500
ALLEN      1600
CLARK      2450
BLAKE      2850
JONES      2975
SCOTT      3000
FORD       3000
KING       5000

14 rows selected.