【问题标题】:How to delete duplicate rows from a table using cursor in oracle?如何使用oracle中的游标从表中删除重复的行?
【发布时间】:2019-01-21 00:10:36
【问题描述】:

我想清理一个有很多重复记录的表。在表中,每个客户号都有很多不同的eff_dt(列名)记录。

我只想为每个客户编号保留一条记录。

为此,我将仅将具有最小 eff_dt 的 cust_nbr 记录作为参考。因此,对于表中的每个 cust_nbr,我只想复制游标上具有最小 eff_dt 的记录,然后将此游标值与表中的其余记录进行比较。

我在创建游标时使用了以下查询:

select cust_nbr, min(eff_dt), name, address from cust;

但这给了我以下错误:

[错误] 执行 (1:8): ORA-00937: not a single-group group function

请帮我解决这个问题

【问题讨论】:

    标签: oracle plsql duplicates cursor self-join


    【解决方案1】:

    您遇到的错误意味着未聚合的列应该是 GROUP BY 子句的一部分,即

    select cust_nbr, min(eff_dt), name, address
    from cust
    group by cust_nbr, name, address;
    

    附:请注意,逐行删除重复项(在游标循环中)是逐个缓慢。您最好切换到某种 set 处理。一个简单的方法是:

    delete from cust
          where (cust_nbr,
                 eff_dt,
                 name,
                 address) not in (  select cust_nbr,
                                           min (eff_dt),
                                           name,
                                           address
                                      from cust
                                  group by cust_nbr, name, address);
    

    【讨论】:

    • 嗨..感谢您的帮助..但是如果具有不同 eff_dt 的其他记录与游标值有任何差异,我想保留该新记录并删除游标中的记录。所以,下一次,我将用这个新记录来比较下一个。为了比较,我使用光标。
    • 不客气。好吧,如果你想做一些额外的处理并找到游标是最合适的解决方案,那就去吧。
    【解决方案2】:

    我不确定游标逻辑的用途。我会简单地删除重复项:

    delete cust
    where  rowid in
           ( select lead(rowid) over (partition by cust_nbr order by eff_dt)
             from   cust c );
    

    【讨论】:

      【解决方案3】:

      以下内容应该适合您:

      DELETE cust c
       WHERE EXISTS (SELECT 1 FROM cust
                      WHERE cust_nbr = c.cust_nbr
                        AND name     = c.name
                        AND address  = c.address
                        AND eff_dt   < c.eff_dt)
      

      【讨论】:

        【解决方案4】:

        如果我理解正确,您有两组数据要删除:

        • 在最近一次更改之前对客户数据(姓名、地址...)进行更改的所有行;
        • 所有行最新更改之后,其中只有 eff_dt 被更改,其他所有内容都相同。

        如果是这种情况,您可以使用两个分析函数来找出客户数据最新变化的最短日期:

        create table test_tab(id number, eff_dt date, name varchar2(20), address varchar2(50));
        
        insert into test_tab values (1, to_date('01-jul-2018', 'dd-mon-yyyy'), 'Name 1', 'Address 1');
        insert into test_tab values (1, to_date('15-jul-2018', 'dd-mon-yyyy'), 'Name 1', 'Address 1');
        insert into test_tab values (1, to_date('01-aug-2018', 'dd-mon-yyyy'), 'Name 1 changed', 'Address 1 changed');
        insert into test_tab values (1, to_date('05-aug-2018', 'dd-mon-yyyy'), 'Name 1 changed', 'Address 1 changed');
        insert into test_tab values (1, to_date('10-aug-2018', 'dd-mon-yyyy'), 'Name 1 changed', 'Address 1 changed');
        insert into test_tab values (2, to_date('12-jul-2018', 'dd-mon-yyyy'), 'Name 2', 'Address 2');
        insert into test_tab values (2, to_date('18-jul-2018', 'dd-mon-yyyy'), 'Name 2', 'Address 2');
        insert into test_tab values (3, to_date('15-jul-2018', 'dd-mon-yyyy'), 'Name 3', 'Address 3');
        insert into test_tab values (3, to_date('18-jul-2018', 'dd-mon-yyyy'), 'Name 3 changed', 'Address 3 changed');
        insert into test_tab values (3, to_date('25-jul-2018', 'dd-mon-yyyy'), 'Name 3 changed again', 'Address 3 changed again');
        insert into test_tab values (3, to_date('12-aug-2018', 'dd-mon-yyyy'), 'Name 3 changed again', 'Address 3 changed again');
        
        select id, eff_dt, name, address, -- rn, min_eff_dt
          from (select id, eff_dt, name, address, -- min_eff_dt,
                       row_number() over (partition by id order by min_eff_dt desc) rn -- we need the highest minimum date - that is the date when last change in data took place (apart from eff_dt)
                  from (select id, eff_dt, name, address,
                               min(eff_dt) over (partition by id, name, address order by eff_dt) min_eff_dt -- minium dates of the customer's data changes
                          from test_tab))
         where rn = 1;
        

        您可以通过删除where rn = 1并将min_eff_dt添加到第二个select语句和rn, min_eff_dt到最上面的select语句来测试脚本,这样您就可以看到解析函数的结果。

        您可以在威廉的回复中使用delete

        delete from test_tab
         where rowid in
                 (select rowid
                    from (select row_number() over (partition by id order by min_eff_dt desc) rn -- we need the highest minimum date - that is the date when last change in data took place (apart from eff_dt)
                            from (select id,
                                         min(eff_dt) over (partition by id, name, address order by eff_dt) min_eff_dt -- minium dates of the customer's data changes
                                    from test_tab))
                   where rn > 1);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-10-06
          • 2023-03-03
          • 2015-09-27
          • 2014-06-13
          • 1970-01-01
          • 2019-10-10
          相关资源
          最近更新 更多