Oracle SQL 显示来自同一个表的匹配数据
Posted
技术标签:
【中文标题】Oracle SQL 显示来自同一个表的匹配数据【英文标题】:Oracle SQL showing matching data from same table 【发布时间】:2020-08-10 06:15:10 【问题描述】:您好,我有下表:
Id Code Acct
=================
1 002 123456
1 004 123456
2 004 456789
2 004 123456
3 001 3456456
4 005 975236
5 006 146387
6 004 0054321
6 010 123456
7 008 165432
7 007 987654
7 002 123456
我需要通过以下方式找到匹配Code
和Acct
的ID:
Code Acct Id1 Id2
=====================
002 123456 1 7
004 123456 1 2
【问题讨论】:
【参考方案1】:自连接(第 1 - 15 行代表样本数据;您需要的查询从第 16 行开始):
SQL> with test (id, code, acct) as
2 (select
3 1, '002', 123456 from dual union all select
4 1, '004', 123456 from dual union all select
5 2, '004', 456789 from dual union all select
6 2, '004', 123456 from dual union all select
7 3, '001', 3456456 from dual union all select
8 4, '005', 975236 from dual union all select
9 5, '006', 146387 from dual union all select
10 6, '004', 0054321 from dual union all select
11 6, '010', 123456 from dual union all select
12 7, '008', 165432 from dual union all select
13 7, '007', 987654 from dual union all select
14 7, '002', 123456 from dual
15 )
16 select a.code, a.acct, a.id id1, b.id id2
17 from test a join test b on a.code = b.code
18 and a.acct = b.acct
19 and a.id > b.id
20 order by code, acct;
COD ACCT ID1 ID2
--- ---------- ---------- ----------
002 123456 7 1
004 123456 2 1
SQL>
【讨论】:
谢谢你的回复,不过,我有一个很大的表,只是展示了它的一部分,所以如何处理大表,因为几乎不可能。 WITH 分解子句只是当您想展示某事物如何工作时创建示例数据的一种简单方法。您的表中已经有数据。您可能感兴趣的代码从第 16 行开始。【参考方案2】:只使用聚合:
select code, account, min(id), max(id)
from t
group by code, account
having count(*) > 1;
注意:这只会返回两个匹配的示例 ID。如果你想要所有这些,你可以使用listagg()
:
select code, account, listagg(id, ',') within group (order by id) as ids
from t
group by code, account
having count(*) > 1;
【讨论】:
【参考方案3】:如果您有任意数量的重复项(即,可能超过 2 个),或者您希望单次通过表,您可以使用一些分析 SQL
SQL> with t as
2 (
3 select 1 id, 002 code, 123456 acct from dual union all
4 select 1, 004 , 123456 acct from dual union all
5 select 2, 004 , 456789 acct from dual union all
6 select 2, 004 , 123456 acct from dual union all
7 select 3, 001 , 3456456 acct from dual union all
8 select 4, 005 , 975236 acct from dual union all
9 select 5, 006 , 146387 acct from dual union all
10 select 6, 004 , 0054321 acct from dual union all
11 select 6, 010 , 123456 acct from dual union all
12 select 7, 008 , 165432 acct from dual union all
13 select 7, 007 , 987654 acct from dual union all
14 select 7, 002 , 123456 acct from dual
15 ),
16 dups as (
17 select t.*,
18 count(*) over ( partition by code,acct ) as dup_cnt
19 from t
20 )
21 select code, acct, listagg(id,',') within group ( order by id) as id_list
22 from dups
23 where dup_cnt > 1
24 group by code, acct;
CODE ACCT ID_LIST
---------- ---------- ------------------------------
2 123456 1,7
4 123456 1,2
【讨论】:
您可以完全删除 dups 子查询,而只需使用HAVING COUNT(*) > 1
。
非常感谢,是的,我确实有超过两场比赛。唯一的问题是我的桌子很大,只是展示了其中的一部分。那么,如何为大表创建 WITH 子句。【参考方案4】:
您可以先使用LISTAGG
,然后再使用REGEXP_SUBSTR
。
SELECT CODE,
ACCT,
REGEXP_SUBSTR (CONCT,
'[^,]+',
1,
1)
ID1,
REGEXP_SUBSTR (CONCT,
'[^,]+',
1,
2)
AS ID2
FROM (WITH MAIN
AS (SELECT 1 AS ID, '002' AS CODE, '123456' AS ACCT FROM DUAL
UNION ALL
SELECT 1 AS ID, '004' AS CODE, '123456' AS ACCT FROM DUAL
UNION ALL
SELECT 2 AS ID, '004' AS CODE, '456789' AS ACCT FROM DUAL
UNION ALL
SELECT 2 AS ID, '004' AS CODE, '123456' AS ACCT FROM DUAL
UNION ALL
SELECT 3 AS ID, '001' AS CODE, '3456456' AS ACCT FROM DUAL
UNION ALL
SELECT 4 AS ID, '005' AS CODE, '975236' AS ACCT FROM DUAL
UNION ALL
SELECT 5 AS ID, '006' AS CODE, '146387' AS ACCT FROM DUAL
UNION ALL
SELECT 6 AS ID, '004' AS CODE, '0054321' AS ACCT FROM DUAL
UNION ALL
SELECT 6 AS ID, '010' AS CODE, '123456' AS ACCT FROM DUAL
UNION ALL
SELECT 7 AS ID, '008' AS CODE, '165432' AS ACCT FROM DUAL
UNION ALL
SELECT 7 AS ID, '007' AS CODE, '987654' AS ACCT FROM DUAL
UNION ALL
SELECT 7 AS ID, '002' AS CODE, '123456' AS ACCT FROM DUAL)
SELECT A.CODE,
A.ACCT,
LISTAGG (A.ID, ',') WITHIN GROUP (ORDER BY A.ID) AS CONCT
FROM MAIN A
GROUP BY A.CODE, A.ACCT)
【讨论】:
【参考方案5】:你可以试试这个。
SQLFiddle
WITH CTE1 AS (
SELECT * FROM TABLE1 WHERE (CODE, ACCT) IN (
SELECT CODE, ACCT FROM (
select count(1), CODE, ACCT FROM TABLE1
GROUP BY CODE, ACCT HAVING COUNT(1) > 1) T))
SELECT X.ID ID1, Y.ID ID2, X.CODE, X.ACCT FROM CTE1 X, CTE1 Y WHERE X.CODE = Y.CODE AND X.ACCT
= Y.ACCT AND X.ID > Y.ID;
【讨论】:
以上是关于Oracle SQL 显示来自同一个表的匹配数据的主要内容,如果未能解决你的问题,请参考以下文章
我的 Oracle SQL 代码正在编译我的代码块,该代码块将游标用于来自两个表的循环,但 dbms 输出行未显示结果