sql中的union子句
Posted
技术标签:
【中文标题】sql中的union子句【英文标题】:union clause in sql 【发布时间】:2012-08-21 15:00:16 【问题描述】:给出下表描述:
emp :
ename varchar2(25)
dept:
loc varchar2(25)
我有以下3个案例:
select ename,to_number(null) from emp
union
select to_char(null),loc from dept;
select ename,to_number(null) from emp
union
select to_number(null),loc from dept;
select ename,null from emp
union
select null,loc from dept;
案例 1 完美执行。
案例 2 执行失败。
案例 3 也完美执行。
我的理解是,我们需要确保如果没有对应的union列,那么我们需要创建一个等效的数据类型dummy。因此,number
类型在另一个表的相应列列表中具有类似 to_number(null)
的内容。
在情况 3 中,我们指定全部为 null,所以我有点理解这种情况。但是在情况 1 中,loc
和 to_number
之间没有数据类型兼容性,但它执行。另一方面,案例 2 失败。请澄清。
【问题讨论】:
你在使用什么 rdbms? mysql、sql-server、Oracle 甲骨文。只是更新标签。对不起。 +1 这其实是一个很好很有趣的问题 @Jim 和大家:OP 想知道为什么案例 1 没有失败。案例 2 按预期失败。 @Adrian 感谢您明确指出这一点。 :-) 【参考方案1】:这个答案可能有点啰嗦……
Oracle 对集合操作非常挑剔。每一列的数据类型必须与第二个、第三个等查询中对应的数据类型相同。
我认为您的第二个查询失败了,因为 Oracle 将 to_number()
评估为一个数字在执行 union
之前,但将其评估为“null-ness”之后。您的第一个查询成功,因为第一个值已被评估为“null-ness”,然后出现 union
。这意味着评估的顺序是:
-
第一个选择函数
第一个选择数据类型
第二个选择函数
联合
第二次选择数据类型
我将尝试一步一步地证明这一点,但我不确定它是否构成绝对证明。
以下两个查询
select 1 from dual union select '1' from dual;
select '1' from dual union select 1 from dual;
将失败并出现以下错误,因为没有进行隐式转换。
ORA-01790: 表达式必须与对应的数据类型相同 表达
但是,以下两个都会成功
select null from dual union select '1' from dual;
select null from dual union select 1 from dual;
如果我们选择这两个查询中的dump
,则会返回以下内容:
SQL> select dump(a)
2 from ( select null a from dual union select '1' from dual );
DUMP(A)
-------------------------------------------------------------------
Typ=96 Len=1: 49
NULL
SQL> select dump(a)
2 from ( select null a from dual union select 1 from dual );
DUMP(A)
-------------------------------------------------------------------
Typ=2 Len=2: 193,2
NULL
如您所见,列有different data-types。第一个查询,有一个字符,返回一个char
,第二个返回一个数字,但是顺序已经颠倒了,第二个select
先来。
最后,如果我们查看您的第一个查询的dump
SQL> select substr(dump(ename),1,35) a, substr(dump(loc),1,35) b
2 from ( select ename,to_number(null) as loc from emp
3 union
4 select to_char(null),loc from dept
5 );
A B
----------------------------------- -----------------------------------
Typ=1 Len=6: 104,97,104,97,104,97 NULL
NULL Typ=1 Len=6: 104,97,104,97,104,97
SQL>
可以看到dump(to_number(null))
为空;但是正在返回 varchar2
而不是 char
,因为这是您的列的数据类型。有趣的是,返回语句的顺序并未颠倒,如果您将此查询创建为表,则两列都是varchar2
。
在选择查询中确定列的数据类型时,Oracle 采用第一个已知数据类型,然后使用它来计算整体数据类型。这就是为什么第一个 select
为空的查询的行被颠倒的原因。
您的第一个查询成功,因为第一个选择 select ename,to_number(null) from emp
“描述”了结果集的外观。 |varchar2|null|
。然后第二个查询添加了|varchar2|varchar2|
,这不会导致任何问题。
您的第二个查询失败,因为第一个选择 select ename,to_number(null) from emp
将结果集“描述”为 varchar2, null
。但是,您随后尝试在 union
中添加一个空数字和一个 varchar2。
这里的信念飞跃是甲骨文决定to_number(null)
是一个数字之前 union
并且直到之后才评估它是否为“null-ness”。我真的不知道如何测试这是否真的发生,因为您无法使用 null
列创建对象,并且您注意到您也无法选择它。
由于我无法证明 Oracle 不允许的事情,我将尝试寻找经验证据。考虑以下查询的结果(或错误)。
SQL> select 1 as a from dual union select to_number(null) from dual;
A
----------
1
SQL> select '1' as a from dual union select to_number(null) from dual;
select '1' as a from dual union select to_number(null) from dual
*
ERROR at line 1:
ORA-01790: expression must have same datatype as corresponding expression
SQL> select 1 as a from dual union select to_char(null) from dual;
select 1 as a from dual union select to_char(null) from dual
*
ERROR at line 1:
ORA-01790: expression must have same datatype as corresponding expression
SQL> select '1' as a from dual union select to_char(null) from dual;
A
-
1
他们似乎证明了 to_char
和 to_number
,无论它们是否在 null 上执行,都隐含地定义了一个数据类型,然后在评估它之前评估它在 union
中的适用性“虚无”
这种解释也将涵盖coalesce
问题,因为to_number(null)
是一个数字之前它是一个空值。
【讨论】:
惊人的惊人答案!感谢您不厌其烦地写下和澄清了这么多!谢谢! :-) 没问题@KazekageGaara,虽然我不完全确定这相当于一个解释:-)... 绰绰有余。 :-) 向我解释了很多。以上是关于sql中的union子句的主要内容,如果未能解决你的问题,请参考以下文章
ORACLE 11G 中的 WITH 子句使用 UNION ALL
我可以在 SQL 中使用 UNION 子句的查询中添加 ORDER BY 子句吗?