【问题标题】:Oracle SQL showing matching data from same tableOracle SQL 显示来自同一个表的匹配数据
【发布时间】: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

【问题讨论】:

    标签: sql oracle sqlplus


    【解决方案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;
        

        【讨论】:

          猜你喜欢
          • 2020-07-10
          • 2016-11-26
          • 1970-01-01
          • 2022-01-18
          • 1970-01-01
          • 2021-04-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多