【问题标题】:Oracle PL/SQL: How to find duplicate sequences in large table?Oracle PL/SQL:如何在大表中查找重复序列?
【发布时间】:2016-08-03 18:23:16
【问题描述】:

我有一个这样的 ~20000 行表(seq = 序列):

id    seq_num   seq_count   seq_id    a    b    c    d
----------------------------------------------------
1     1         3           A400      1    0    0    0
2     2         3           A400      0    1    0    0
3     3         3           A400      0    0    1    0
4     1         2           V2303     1    1    1    1
5     2         2           V2303     1    1    1    1
6     1         3           G2        1    0    0    0
7     2         3           G2        0    1    0    0
8     3         3           G2        0    0    1    0
9     1         3           U900      1    0    0    0
10    2         3           U900      2    2    1    1
11    3         3           U900      5    3    8    5

我想找到在表中有重复的 a-b-c-d 序列的 seq_id,可能只是 dbms_ouput.put_line 或任何东西。如您所见,seq_id G2 是 A400 的副本,因为它们的所有行都匹配,但 U900 没有重复,即使有一行匹配 A400 和 G2。

有没有一种好方法可以在大量数据上检查这样的重复项?我无法创建新表来临时保存数据。到目前为止,我一直在尝试使用游标,但没有运气。

谢谢,如果您需要有关我的问题的更多信息,请告诉我。

【问题讨论】:

  • 如果您发布遇到问题的查询会很有帮助。

标签: sql oracle plsql duplicates


【解决方案1】:

Oracle 设置

CREATE TABLE table_name ( id, seq_num, seq_count, seq_id, a, b, c, d ) AS
SELECT 1,  1, 3, 'A400',  1, 0, 0, 0 FROM DUAL UNION ALL
SELECT 2,  2, 3, 'A400',  0, 1, 0, 0 FROM DUAL UNION ALL
SELECT 3,  3, 3, 'A400',  0, 0, 1, 0 FROM DUAL UNION ALL
SELECT 4,  1, 2, 'V2303', 1, 1, 1, 1 FROM DUAL UNION ALL
SELECT 5,  2, 2, 'V2303', 1, 1, 1, 1 FROM DUAL UNION ALL
SELECT 6,  1, 3, 'G2',    1, 0, 0, 0 FROM DUAL UNION ALL
SELECT 7,  2, 3, 'G2',    0, 1, 0, 0 FROM DUAL UNION ALL
SELECT 8,  3, 3, 'G2',    0, 0, 1, 0 FROM DUAL UNION ALL
SELECT 9,  1, 3, 'U900',  1, 0, 0, 0 FROM DUAL UNION ALL
SELECT 10, 2, 3, 'U900',  2, 2, 1, 1 FROM DUAL UNION ALL
SELECT 11, 3, 3, 'U900',  5, 3, 8, 5 FROM DUAL;

查询

SELECT  s.seq_id,
        t.seq_id AS matched_seq_id
FROM    table_name s
        INNER JOIN
        table_name t
        ON (    s.seq_num = t.seq_num 
            AND s.seq_count = t.seq_count
            AND s.seq_id   < t.seq_id
            AND s.a = t.a
            AND s.b = t.b
            AND s.c = t.c
            AND s.d = t.d )
GROUP BY
        t.seq_id,
        s.seq_id
HAVING  COUNT( DISTINCT t.seq_num ) = MAX( t.seq_count );

结果

SEQ_ID MATCHED_SEQ_ID
------ --------------
A400   G2             

【讨论】:

    【解决方案2】:

    假设结果适合大约 2000 个字符长的字符串,最快的方法可能是使用listagg()

    select abcds, listagg(seq_id, ',') within group (order by seq_id)
    from (select seq_id, listagg(a||b||c||d, ',') within group (order by seq_num) as abcds
          from table_name
          group by seq_id
         ) t
    group by abcds
    having count(*) >= 2;
    

    这会将匹配项以逗号分隔的列表形式返回。

    【讨论】:

    • ORDER BY seq_count 不是不确定的,因为它们在组内都具有相同的计数吗?做ORDER BY seq_num不是更好吗?
    • @MTO 。 . .谢谢。
    • 谢谢 Gordon,LISTAGG 正是我所需要的。我正在考虑将序列连接成长字符串,但我不确定字符串长度的限制,我的实际表有大约 15 列要比较,序列中最多有 20 行。作为一个额外的问题,我现在被告知序列可以像这样旋转:1 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 = 1 0 0 0 =/= 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 我也应该检查这些等价性。
    • 对不起,我的旋转插图搞砸了,不知道如何在评论中格式化它。本质上 123 = 312 =/= 132
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    相关资源
    最近更新 更多