【问题标题】:SQL search and destroy duplicatesSQL 搜索和销毁重复项
【发布时间】:2010-01-31 16:29:40
【问题描述】:

我有一个包含字段的表格(简化):

id, fld1, fld2, fld3.

id 是一个数字主键字段。

存在重复:id 不同,但 fld1fld2fld3 在 2 行或更多行上相同。当然,也有一些条目的值只出现一次,即不重复。

在每组重复条目中,我只想保留 ID 最高的条目。我打算先列出注定要失败的行,然后再删除它们。

我的第一次尝试是这样的:

SELECT * FROM tab1 t1 WHERE EXISTS (
  SELECT COUNT(*) FROM tab1 t2
  WHERE t1.fld1 = t2.fld1 AND t1.fld2 = t2.fld2 AND t1.fld3 = t2.fld3
    AND t1.id < MAX(t2.id)
  HAVING COUNT(*) > 1
  GROUP BY t2.fld1, t2.fld2, t2.fld3)

但是(在 Oracle 中)我收到了 Missing right parenthesis 错误消息。我认为这完全需要一种新方法,但我的 SQL-fu 不能胜任这项任务。感谢您的帮助!


编辑:

使用“真实”数据字段:

select x.leg_id, x.airline_des, x.flight_nr, x.suffix, x.flight_id_date, x.lt_flight_id_date
from fdb_leg x
join ( select max(t.leg_id) 'max_id', 
t.airline_des, t.flight_nr, t.suffix, t.flight_id_date, t.lt_flight_id_date
from fdb_leg t
group by t.airline_des, t.flight_nr, t.suffix, t.flight_id_date, t.lt_flight_id_date
having count(*) > 1) y on y.max_id > x.leg_id
and y.airline_des = x.airline_des and y.flight_nr = x.flight_nr and y.suffix = x.suffix
and y.flight_id_date = x.flight_id_date and x.lt_flight_id_date = y.lt_flight_id_date

回复是:

ORA-00923:在预期的地方找不到 FROM 关键字

【问题讨论】:

  • HAVING 出现在 GROUP BY 之后
  • 9i,我想。是否有来自 DUAL 的 SELECT 版本?
  • 尝试运行:SELECT * FROM v$version WHERE banner LIKE 'Oracle%'
  • 啊,是的。 Oracle9i Enterprise Edition Release 9.2.0.8.0 - Production.
  • Re: ORA-00923 错误,请尝试将 MAX(t.leg_id) 'max_id' 替换为 MAX(t.leg_id) AS max_id。不知道你在用什么,但我知道 Toad for Oracle 不喜欢用单引号来定义列别名。

标签: sql oracle duplicates oracle9i


【解决方案1】:

Oracle 9i+,使用 WITH:


要获取注定失败的条目列表,请使用:

WITH keepers AS (
   SELECT MAX(t.id) 'max_id',
          t.fld1, t.fld2, t.fld3
     FROM TABLE_1 t
 GROUP BY t.fld1, t.fld2, t.fld3
   HAVING COUNT(*) > 1)
SELECT x.id,
       x.fld1, x.fld2, x.fld3
  FROM TABLE_1 x
  JOIN keepers y ON y.max_id > x.id
                AND y.fld1 = x.fld1
                AND y.fld2 = x.fld2
                AND y.fld3 = x.fld3

非 WITH 等价物:


要获取注定失败的条目列表,请使用:

SELECT x.id,
       x.fld1, x.fld2, x.fld3
  FROM TABLE_1 x
  JOIN (SELECT MAX(t.id) 'max_id',
               t.fld1, t.fld2, t.fld3
          FROM TABLE_1 t
      GROUP BY t.fld1, t.fld2, t.fld3
        HAVING COUNT(*) > 1) y ON y.max_id > x.id
                              AND y.fld1 = x.fld1
                              AND y.fld2 = x.fld2
                              AND y.fld3 = x.fld3

【讨论】:

  • 如果更容易正确,我也可以使用 WITH 解决方案。
  • @Carl Smotricz:它们是等价的——理论上你应该得到同样的错误。
  • Re: ORA-00923 错误,请尝试将MAX(t.leg_id) 'max_id' 替换为MAX(t.leg_id) AS max_id。不知道你在用什么,但我知道 Toad for Oracle 不喜欢用单引号来定义列别名。
  • 确实,它执行了! AS max_id 似乎做到了。结果看起来也很合理。
  • @Carl Smotricz:睡眠适合弱者。通过 JDBC 的 SQL 意味着如果单引号没有正确转义,它们很可能会与查询混淆。
【解决方案2】:

您可以一次性删除它们,如下所示:

SQL> create table mytable (id, fld1, fld2, fld3)
  2  as
  3  select 1, 1, 1, 1 from dual union all
  4  select 2, 1, 1, 1 from dual union all
  5  select 3, 2, 2, 2 from dual union all
  6  select 4, 2, 3, 2 from dual union all
  7  select 5, 2, 3, 2 from dual union all
  8  select 6, 2, 3, 2 from dual
  9  /

Table created.

SQL> delete mytable
  2   where id not in
  3         ( select max(id)
  4             from mytable
  5            group by fld1
  6                , fld2
  7                , fld3
  8         )
  9  /

3 rows deleted.

SQL> select * from mytable
  2  /

        ID       FLD1       FLD2       FLD3
---------- ---------- ---------- ----------
         2          1          1          1
         3          2          2          2
         6          2          3          2

3 rows selected.

问候, 抢。

【讨论】:

  • 看起来不错,可以说比 OMG Ponies 更简单。我将在今天晚些时候尝试一下。谢谢!
  • +1:这是更好的答案。另请注意,NOT INLEFT JOIN/IS NULLNOT EXISTS 在 Oracle 中具有相同的性能:explainextended.com/2009/09/17/…
  • @OMG Ponies:感谢您的确认!这就是我最终使用的,它似乎做得很好。性能不是什么大问题,因为它是夜间批处理。
【解决方案3】:

嗯,我明白了。从头开始。

这将标识需要删除的 ID。

Select 
       fld1
     , fld2
     , fld3
     , Max(ID)
From table_name
Group By
       fld1
     , fld2
     , fld3

【讨论】:

  • 实际上,这将列出 OP 想要保留的记录:“...我只想保留 ID 最高的条目...”
  • @Jeff O:这看起来是错误的,原因有两个:(1)有许多非重复行,这将列出所有不同的行; (2) 我想删除的不是最大值行,而是所有具有较小键的行。
猜你喜欢
  • 2013-07-12
  • 2014-09-07
  • 1970-01-01
  • 1970-01-01
  • 2018-12-04
  • 2012-05-07
  • 2011-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多