Oracle SQL——如何使用首选项删除部分重复项

Posted

技术标签:

【中文标题】Oracle SQL——如何使用首选项删除部分重复项【英文标题】:Oracle SQL -- how to delete partial duplicates with a preference 【发布时间】:2017-12-28 06:22:37 【问题描述】:

您能帮我从表中删除重复项(部分)吗?我有一个包含 5 列的表。在这张表中,我有重复项——但只有 4 列是相同的,其中一列(field5)是不同的。那就是:

F1 F2 F3 F4 F5
A1 A2 A3 A4 103
A1 A2 A3 A4 3

因此,对于重复项,4 列/字段是相同的,除了第 5 个。我想删除包含数字“103”的行,即更高的数字。我怎样才能做到这一点?

如果这是一个正常的副本,我会使用 max(rowid) 并删除该行。但是现在这可以删除包含较低数字而不是较高数字的行。

我能想到的一种方法是创建一个新表,其中包含重复的行,并且 Field5 在该表中具有更高的数字。然后通过将其与此新表进行比较来从原始表中删除行。但这对我来说似乎不是很好的解决方案——尤其是如果原始表很大,这可能需要很长时间。

任何帮助将不胜感激。谢谢。

【问题讨论】:

【参考方案1】:

想法是记录F1,F2,F3,F4 的每个组合并删除其余的。

试试这个:

    DELETE FROM TABLE_NAME WHERE ROWID IN 
    (SELECT ROWID FROM 
        (SELECT ROWID, row_number() OVER(PARTITION BY F1,F2,F3,F4 ORDER BY F5) RN 
           FROM TABLE_NAME)
    WHERE RN<>1);

【讨论】:

这会引发 ORA-01446:无法从具有 DISTINCT、GROUP BY 等的视图中选择 ROWID 或对其进行采样。但是,如果您删除 ROWNUM,它将起作用。 非常感谢您的帖子!这个完美。上一篇文章提出了 Littlefoot 指定的错误。如果我可以选择,这对我来说将是最好的解决方案:)【参考方案2】:

这个怎么样?

SQL> select * from test order by f1, f5;

F1 F2 F3 F4         F5
-- -- -- -- ----------
a1 a2 a3 a4          3
a1 a2 a3 a4         50  --> delete
a1 a2 a3 a4        103  --> delete
b1 b2 b3 b4          2
b1 b2 b3 b4        200  --> delete
c1 c2 c3 c4          1

6 rows selected.

SQL> delete from test t
  2        where rowid not in (select rowid
  3                              from test t1
  4                             where     t1.f1 = t.f1
  5                                   and t1.f2 = t.f2
  6                                   and t1.f3 = t.f3
  7                                   and t1.f4 = t.f4
  8                                   and t1.f5 =
  9                                          (select min (t2.f5)
 10                                             from test t2
 11                                            where     t2.f1 = t.f1
 12                                                  and t2.f2 = t.f2
 13                                                  and t2.f3 = t.f3
 14                                                  and t2.f4 = t.f4));

3 rows deleted.

SQL> select * from test order by f1, f5;

F1 F2 F3 F4         F5
-- -- -- -- ----------
a1 a2 a3 a4          3
b1 b2 b3 b4          2
c1 c2 c3 c4          1

SQL>

【讨论】:

非常感谢小脚!你的回答太棒了!并感谢您在第一篇文章中指出问题。我不知道这可以通过我自己知道的东西/概念来解决:) 所以,感谢指出这样的解决方案。此解决方案的唯一缺点是,当表中有很多列时,行数过多。【参考方案3】:

我通常只是这样做:

delete demo
where  rowid in
       ( select lead(rowid) over (partition by f1, f2, f3, f4 order by f5) as next_rowid
         from   demo );

也就是说,在其(f1, f2, f3, f4) 组中按f5 的顺序删除每个“下一个”行。

【讨论】:

感谢您的回答!这是一个有趣的解决方案。我实际上首先有疑问,但看起来它按预期工作。

以上是关于Oracle SQL——如何使用首选项删除部分重复项的主要内容,如果未能解决你的问题,请参考以下文章

Oracle中如何删除重复数据

Oracle SQL:如何删除 listagg 中的重复项

如何解决Oracle数据库中重复数据的方法步骤

oracle数据库中如何用sql语句查出重复字段以及如何删除?

使用 SQL 和 JavaScript 的用户首选项

PL/SQl,oracle 9i,使用sql删除重复行