📜  使用集合运算符

📅  最后修改于: 2020-12-29 04:22:59             🧑  作者: Mango


集合运算符是用来连接Oracle中提供两个(或更多)SELECT statements.The SET运算符11G是UNION,UNION ALL,INTERSECT,和负的结果。

UNION set运算符返回两个SELECT语句的合并结果。本质上,它从结果中删除重复项,即每个重复的结果仅列出一行。要解决此问题,请使用UNION ALL set运算符将重复项保留在最终结果。INTERSECT仅列出两个SELECT查询共有的记录;如果在第一个查询的结果中也找到第二个查询的结果,则MINUS set运算符将从输出中删除第二个查询的结果。 INTERSECT和MINUS设置操作将产生不重复的结果。

所有SET运算符享有相同的优先级。相反,在查询执行期间,Oracle从左到右或从上到下开始评估。如果使用显式括号,则顺序可能会有所不同,因为括号将优先于悬空运算符。

要记住的要点-

  • 所有参与的SELECT语句必须选择相同数量的列。显示中使用的列名称取自第一个查询。

  • 列列表的数据类型必须可由oracle兼容/隐式转换。如果组件查询中的对应列属于不同的数据类型组,则Oracle不会执行隐式类型转换,例如,如果第一个组件查询中的列属于数据类型DATE,而第二个组件查询中的对应列属于数据类型类型为CHAR,Oracle将不执行隐式转换,但会引发ORA-01790错误。

  • 必须使用位置排序对结果集进行排序。 Set运算符不允许单独的结果集排序。 ORDER BY可以在查询末尾出现一次。例如,

  • UNION和INTERSECT运算符是可交换的,即查询的顺序并不重要。它不会改变最终结果。

  • 在性能方面,由于UNION ALL在筛选重复项和对结果集进行排序时不会浪费资源,因此与UNION相比,它表现出更好的性能。

  • 集运算符可以是子查询的一部分。

  • 集合运算符不能用于包含TABLE集合表达式的SELECT语句中。

  • 该LONG,BLOB,CLOB,BFILE,VARRAY或嵌套表。对于UPDATE子句不与集合运算符允许不得用于设置运算符使用。

联盟

当使用UNION运算符联接多个SELECT查询时,在删除所有重复项并按排序顺序(默认情况下升序)后,Oracle将显示所有复合SELECT查询的合并结果,而不会忽略NULL值。

考虑以下五个使用UNION运算符联接的查询。最终的组合结果集包含所有SQL的值。注意重复删除和数据排序。

SELECT 1 NUM FROM DUAL
UNION
SELECT 5 FROM DUAL 
UNION
SELECT 3 FROM DUAL
UNION
SELECT 6 FROM DUAL
UNION
SELECT 3 FROM DUAL;

NUM
-------
1
3
5
6

需要注意的是,在SELECT查询中选择的列必须具有兼容的数据类型。违反规则时,Oracle会引发错误消息。

SELECT TO_DATE('12-OCT-03') FROM DUAL
UNION
SELECT '13-OCT-03' FROM DUAL;

SELECT TO_DATE('12-OCT-03') FROM DUAL
       *
ERROR at line 1:
ORA-01790: expression must have same datatype as corresponding expression

全联盟

UNION和UNION ALL在功能上相似,只是稍有不同。但是UNION ALL给出了结果集,而没有删除重复项和对数据进行排序。例如,在上面的查询中,UNION被UNION ALL取代以查看效果。

考虑在UNION部分演示的查询。注意在没有排序和重复数据删除的情况下生成的输出差异。

SELECT 1 NUM FROM DUAL
UNION ALL
SELECT 5 FROM DUAL 
UNION ALL
SELECT 3 FROM DUAL
UNION ALL
SELECT 6 FROM DUAL
UNION ALL
SELECT 3 FROM DUAL;

NUM
-------
1
5
3
6
3

相交

使用INTERSECT运算符,Oracle将显示两个SELECT语句中的公共行,没有重复项,并且数据没有按排序顺序排列(默认情况下升序)。

例如,下面的SELECT查询检索部门10和部门20中常见的薪水。按照ISO SQL标准,INTERSECT在评估集合运算符位于其他位置,但是Oracle仍未合并。

SELECT SALARY
FROM employees
WHERE DEPARTMENT_ID = 10
INTRESECT
SELECT SALARY 
FROM employees
WHERE DEPARTMENT_ID = 20

SALARY
---------
1500
1200
2000

减去

减号运算符显示在第一个查询中存在但在第二个查询中不存在的行,默认情况下没有重复和数据以升序排列。

SELECT JOB_ID
FROM employees
WHERE DEPARTMENT_ID = 10
MINUS
SELECT JOB_ID
FROM employees
WHERE DEPARTMENT_ID = 20;

JOB_ID
-------------        
HR
FIN
ADMIN

匹配SELECT语句

在某些情况下,复合SELECT语句可能具有不同的选定列计数和数据类型。因此,为了显式匹配列列表,在缺少的位置插入NULL列,以匹配每个SELECT语句中所选列的计数和数据类型。对于数字列,也可以将零替换为匹配查询中所选列的类型。

在以下查询中,员工姓名(varchar2)和位置ID(number)的数据类型不匹配。因此,由于兼容性问题,执行以下查询将引发错误。

SELECT DEPARTMENT_ID "Dept", first_name "Employee"
FROM employees
UNION
SELECT DEPARTMENT_ID, LOCATION_ID
FROM departments;

ERROR at line 1:
ORA-01790: expression must have same datatype as corresponding expression

明确地,可以通过用NULL代替位置ID和员工名称来匹配列。

SELECT DEPARTMENT_ID "Dept", first_name "Employee", NULL "Location"
FROM employees
UNION
SELECT DEPARTMENT_ID, NULL "Employee", LOCATION_ID
FROM departments;

在SET操作中使用ORDER BY子句

在包含复合SELECT语句的查询末尾,ORDER BY子句只能出现一次,这意味着单个SELECT语句不能具有ORDER BY子句。此外,排序可以仅基于第一个SELECT查询中出现的列。因此,建议使用列位置对复合查询进行排序。

下面的compund查询统一了两个部门的结果,并按SALARY列进行排序。

SELECT employee_id, first_name, salary
FROM employees
WHERE department_id=10
UNION
SELECT employee_id, first_name, salary
FROM employees
WHERE department_id=20
ORDER BY 3;