Oracle 取两个表中数据的交集

本文介绍Oracle数据库中使用INTERSECT操作符及关系SQL获取两个表的交集数据的方法,并对比了NOT EXISTS与NOT IN的区别。

 关键字: Oracle 取两个表中数据的交集 INTERSECT

Oracle 作为一个大型的关系数据库,日常应用中往往需要提取两个表的交集数据

例如现有如下表,要求找出工资2500(不含2500)以上并且是男性(M)的员工编号,那么就要利用这两个表的关系做一个交集了

 

employee

CODE

NAME

GENDER

001TomM
002JerryM
003AnaF

 

 

salary

CODE

SALARY

0012800
0022500
0033000

 

方法1:利用操作符INTERSECT

INTERSECT 操作符用来合并两个查询,返回两个查询中都存在的记录,即返回两个查询结果的交集,前提是两个查询的列的数量和数据类型必须完全相同。

SELECT CODE FROM EMPLOYEE WHERE GENDER = 'M'
INTERSECT
SELECT CODE FROM SALARY WHERE SALARY > 2500

第一条SQL的结果为

CODE
----------
001
002

第二条SQL的结果为

CODE
----------
001
003

INTERSECT的结果

CODE
----------
001

方法2:利用关系SQL

SELECT A.CODE FROM EMPLOYEE A, SALARY B
WHERE A.CODE = B.CODE AND A.GENDER = 'M' AND B.SALARY > 2500

结果为

CODE
----------
001

以上两种方法是本人比较常用的方法,尤其第二种,充分体现关系数据的精髓所在。但如果两个表结构比较复杂,而且关系条件也比较难实现的话,第一种显然能够简单地得到需要的结果,也不失为一种好方法。

 

如果用exists的话还是用第一种。

 

 

 

先看下面的例子:oracle中两个系统表.emp,dept.

example:

1:not exists(not in)

 not exists:

   这条语句返回select * from scott.dept d where e.deptno=d.deptno and d.deptno=10条件满足的结果集.也就是说,

返回的结果集中不存在d.deptno=10结果集的记录,即emp表中没有dept表中d.deptno=10的记录.

 SQL> select empno,ename,deptno from scott.emp e where not exists(select * from scott.dept d where e.deptno=d.deptno and d.deptno=10);

EMPNO ENAME      DEPTNO
----- ---------- ------
 7369 SMITH          20
 7499 ALLEN          30
 7521 WARD           30
 7566 JONES          20
 7654 MARTIN         30
 7698 BLAKE          30
 7788 SCOTT          20
 7844 TURNER         30
 7876 ADAMS          20
 7900 JAMES          30
 7902 FORD           20

11 rows selected

not in:

第一个where条件必须给定字段(deptno), 第二个sql语句中,必须明确给定要查询的字段是哪个(deptno).

SQL> select empno,ename,deptno from scott.emp e where deptno not in(select deptno from scott.dept d where e.deptno=d.deptno and d.deptno=10);

EMPNO ENAME      DEPTNO
----- ---------- ------
 7369 SMITH          20
 7499 ALLEN          30
 7521 WARD           30
 7566 JONES          20
 7654 MARTIN         30
 7698 BLAKE          30
 7788 SCOTT          20
 7844 TURNER         30
 7876 ADAMS          20
 7900 JAMES          30
 7902 FORD           20

11 rows selected

2: exists(in)

  exists:

   这条语句返回select * from scott.dept d where e.deptno=d.deptno and d.deptno=10条件满足的记录结果集.

也就是说返回的结果集中只存在有d.deptno=10的记录,即emp表中只存在dept表中d.deptno=10的记录.

SQL> select empno,ename,deptno from scott.emp e where  exists(select * from scott.dept d where e.deptno=d.deptno and d.deptno=10);

EMPNO ENAME      DEPTNO
----- ---------- ------
 7782 CLARK          10
 7839 KING           10
 7934 MILLER         10

in:

第一个where条件必须给定字段(deptno), 第二个sql语句中,必须明确给定要查询的字段是哪个(deptno).

SQL> select empno,ename,deptno from scott.emp e where  deptno in(select deptno from scott.dept d where e.deptno=d.deptno and d.deptno=10);

EMPNO ENAME      DEPTNO
----- ---------- ------
 7782 CLARK          10
 7839 KING           10
 7934 MILLER         10

 

  oracle 中exists (in)和not exists(not in)是判断是否存在和不存在表中记录的关键子.

 请注意:not in 逻辑上不完全等同于not exists,如果你误用了not in,小心你的程序存在致命的BUG:因此,请尽量不要使用not in(它会调用子查询),而尽量使用not exists(它会调用关联子查询)。

<think> 首先,用户的问题是:"我想查找在ORACLE数据库中获两个交集之外部分数据SQL语句 请问ORACLE两个交集之外部分数据SQL语句"。用户正在寻求在Oracle数据库中获两个交集之外部分数据SQL语句。 回顾引用内容: - 引用[1]:展示了使用INNER JOIN或USING子句获两个交集。 - 引用[2]和[3]:讨论了处理两个逗号分隔的字符串以获交集或差集,但用户的问题是关于的,而不是字符串。 - 引用[4]:解释了SQL是面向集合的,并提到了查询的基本结构。 用户明确提到"两个交集之外部分数据",这指的是差集(difference)。在集合操作中,交集是共同部分,差集是两个集合中不同的部分。具体来说,"交集之外"可能意味着: - A中有但B中没有的记录(A - B) - B中有但A中没有的记录(B - A) - 或者两者的对称差(A ∪ B 减去 A ∩ B) 在SQL中,这通常使用EXCEPT 或 MINUS 操作符来实现,但在Oracle中,MINUS 是标准的关键字。 回想OracleSQL语法: - 要获两个交集,可以使用INTERSECT。 - 要获差集(例如,A中有但B中没有),可以使用MINUS(在某些数据库中叫EXCEPT)。 - 另外,也可以使用OUTER JOIN或NOT EXISTS子查询来实现。 用户指定"两个交集之外",所以我需要提供获差集的SQL语句。 结构化我的回答: 1. **理解需求**:解释用户的问题,确认需求。 2. **提供解决方案**: - 使用MINUS操作符。 - 使用LEFT JOIN WHERE IS NULL。 - 使用NOT EXISTS。 3. **给出示例**:基于引用[1],假设有类似的结构(location和store_info)。引用[1]提到了SELECT A.Store_Name FROM location A INNER JOIN store_info B ON A.Store_Name = B.Store_Name; 用于交集。 4. **确保SQL正确**:使用Oracle兼容的语法。 5. **添加相关引用**:如果适用,自然地添加引用标识。引用来自用户提供的文本,但它们是关于SQL的,所以我可以在解释时引用。 6. **生成相关问题**:在最后添加相关问题,作为系统指令的一部分。 7. **使用中文回答**:所有内容用中文。 参考引用结合: - 引用[1]展示了交集查询。 - 引用[4]强调了SQL的集合性质,有助于解释操作。 - 引用[2]和[3]是关于字符串的,不直接相关,但可以忽略或不提及。 示例SQL: 假设有两个:table1 和 table2,有一个公共字段,比如 id。 获交集之外的数据: - 如果用户想要所有不在交集的部分,可能需要对称差: (A - B) ∪ (B - A) - 或者具体指定哪一部分。 通用方法: 1. **获A中有但B中没有:** - 使用MINUS: SELECT column FROM table1 MINUS SELECT column FROM table2; - 使用LEFT JOIN: SELECT A.* FROM table1 A LEFT JOIN table2 B ON A.key = B.key WHERE B.key IS NULL; - 使用NOT EXISTS: SELECT * FROM table1 A WHERE NOT EXISTS (SELECT 1 FROM table2 B WHERE A.key = B.key); 2. **获B中有但A中没有:** 类似,交换位置。 3. **获对称差:** 使用UNION ALL组合两个差集。 在Oracle中,MINUS是有效的。 回答结构: - 先确认需求。 - 提供SQL语句示例。 - 解释每个方法。 - 基于引用[1]的示例,使用location和store_info。 - 最后添加相关问题。 相关问题生成: 1. 如何优化这类查询的性能? 2. 在Oracle中处理大数据量时有哪些最佳实践? 3. 差集操作有哪些常见应用场景? 4. MINUS和EXCEPT有什么区别?(在Oracle中是MINUS) 5. 如何处理有重复记录的情况? 确保LaTeX格式正确:用户提到的数学达式要用$...$,但在这个上下文中,可能不需要数学公式。如果需要,例如解释集合操作,但SQL本身不需要。 最终回答大纲: - 开头:解释交集之外的含义。 - 方法1:使用MINUS操作符。 - 方法2:使用LEFT JOIN。 - 方法3:使用NOT EXISTS。 - 示例代码。 - 结尾:引用和相关问题。 </think> 基于您的查询,您需要在Oracle数据库中获两个交集之外部分数据,即差集(difference set)。在SQL中,"交集之外"通常指那些在一个中存在但在另一个中不存在的记录。主要有两种常见场景: - **A中有但B中没有的记录**(A - B) - **B中有但A中没有的记录**(B - A) - **对称差集**(所有只在A或只在B中的记录,等同于(A - B) ∪ (B - A)) 在Oracle SQL中,可以使用以下几种方法实现差集操作。以下解决方案基于标准SQL语法,结合引用内容中的示例(如引用[1]使用`location`和`store_info`)。假设两个有公共字段(如`store_name`),用于匹配记录。 ### 方法1: 使用`MINUS`操作符(推荐) `MINUS`是Oracle中专用于差集的操作符,直接返回第一个查询结果中存在但第二个查询结果中不存在的记录。 **语法示例:** ```sql -- 获A中有但B中没有的记录 (A - B) SELECT column_name FROM tableA MINUS SELECT column_name FROM tableB; -- 获B中有但A中没有的记录 (B - A) SELECT column_name FROM tableB MINUS SELECT column_name FROM tableA; -- 获对称差集 (A - B) ∪ (B - A) (SELECT column_name FROM tableA MINUS SELECT column_name FROM tableB) UNION ALL (SELECT column_name FROM tableB MINUS SELECT column_name FROM tableA); ``` **示例(基于引用[1]的结构):** 假设`location`和`store_info`都有`store_name`字段。 ```sql -- 获在location中有但store_info中没有的门店 SELECT store_name FROM location MINUS SELECT store_name FROM store_info; -- 获对称差集(所有不重叠的门店) (SELECT store_name FROM location MINUS SELECT store_name FROM store_info) UNION ALL (SELECT store_name FROM store_info MINUS SELECT store_name FROM location); ``` ### 方法2: 使用`LEFT JOIN` + `WHERE IS NULL 这种方法通过左外连接找到A中所有记录,并过滤掉与B匹配的记录。 **语法示例:** ```sql -- A中有但B中没有 SELECT A.* FROM tableA A LEFT JOIN tableB B ON A.key_column = B.key_column WHERE B.key_column IS NULL; -- B中有但A中没有(使用RIGHT JOIN或交换) SELECT B.* FROM tableA A RIGHT JOIN tableB B ON A.key_column = B.key_column WHERE A.key_column IS NULL; ``` **优点:** 灵活,可处理多个字段的匹配;**缺点:** 性能可能不如`MINUS`在大数据量时高效[^4]。 ### 方法3: 使用`NOT EXISTS`子查询 通过子查询检查记录是否存在,适用于复杂条件。 **语法示例:** ```sql -- A中有但B中没有 SELECT * FROM tableA A WHERE NOT EXISTS ( SELECT 1 FROM tableB B WHERE A.key_column = B.key_column ); ``` ### 关键注意事项 1. **字段一致性:** 所有查询中SELECT的字段数量、类型必须相同(如`MINUS`要求字段兼容)。 2. **性能优化:** 对大数据添加索引到连接字段(如`store_name`),以提高速度[^4]。 3. **去重处理:** 上述方法默认去除重复记录;如需保留重复,用`UNION ALL`代替`UNION`。 4. **应用场景:** 适用于数据清洗(如找出新增或删除的记录),或在ETL过程中识别变更[^3]。 ### 示例完整代码 基于引用[1]的名,获`location`中独有的门店: ```sql SELECT store_name FROM location MINUS SELECT store_name FROM store_info; ``` 此查询返回只在`location`中存在的`store_name`值[^1]。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值