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

我需要通过以下方式找到匹配CodeAcct 的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 输出行未显示结果

来自多个表的oracle数据

需要来自 Oracle SQL 查询的父表和子表的 XML

SQL 更新一个表中的值以匹配 Oracle SQL Developer 中另一个表的值

针对提取值的 Oracle sql 连接

MySQL数据库的一个表截取字符串然后去找另一张表的字段匹配怎么写sql