查找重复项并增加值

时间:2017-01-05 11:25:21

标签: sql oracle plsql

我有一个plsql包需要突出显示唯一id字段中的任何重复项,并在发生重复时添加v2,v3。例如,唯一id 111出现三次 - 111,111v2 111v3。

我的代码突出显示重复项,但将每个集视为相同,例如111 v2 111 v2 111 v2

  PROCEDURE find_duplicates IS
      c_amt           INT;
      c_id            VARCHAR2(255);
      c_id_new        VARCHAR2(255);
      v_count         int;

      cursor c_duplicates is
        select UNIQUE_ID,Qty from (
          select UNIQUE_ID, count(*) as Qty from dbo.Temp_Weekly_Export_File
          group by UNIQUE_ID
          having count(*) > 1) where Qty >1;
    BEGIN
       BEGIN
          v_count := 0;

          open c_duplicates;
          LOOP
            FETCH c_duplicates into c_id, c_amt;
            v_count := v_count + 1;
            c_id_new := c_id||'_V'||v_count;

            --DBMS_OUTPUT.PUT_LINE('C_ID: '||c_id);
            UPDATE dbo.Temp_Weekly_Export_File
            SET UNIQUE_ID=c_id_new
            where unique_id=c_id;

            EXIT WHEN c_duplicates%NOTFOUND;
          END LOOP;
      END;
  END;

2 个答案:

答案 0 :(得分:3)

您的代码只会看到每个unqiue_id一次,因为您按该列进行分组;并且对于具有多行的每个ID,您的更新然后将所有这些更新为相同的V编号。并且因为您没有为每个ID重置v_count,所以具有重复项的第一个ID将其所有行更新为V1;带有重复项的第二个ID将全部设置为V2;等

你可以通过合并来做到这一点;目标是获取每一行的ID和rowid的查询,并且源获取这些以及每个ID的计数以及每个ID的每次出现的任意排名(通过分析函数):

create table Temp_Weekly_Export_File (unique_id varchar2(10));
insert into Temp_Weekly_Export_File values ('111');
insert into Temp_Weekly_Export_File values ('111');
insert into Temp_Weekly_Export_File values ('111');
insert into Temp_Weekly_Export_File values ('112');
insert into Temp_Weekly_Export_File values ('112');
insert into Temp_Weekly_Export_File values ('113');

merge into
(
  select unique_id, rowid
  from Temp_Weekly_Export_File
) t
using (
  select unique_id,
    row_number() over (partition by unique_id order by 1) as rnk,
    count(*) over (partition by unique_id) as cnt
  from Temp_Weekly_Export_File
) s
on (s.rowid = t.rowid and s.cnt > 1)
when matched then
update set t.unique_id = s.unique_id ||'_V'||s.rnk;

3 rows merged.

select * from Temp_Weekly_Export_File;

UNIQUE_ID 
----------
111_V1
111_V2
111_V3
112V_1
112V_2
113

on子句必须使用不会被合并本身更新的列,因此它不能只使用unique_id; rowid应该足够稳定了。

如果你有另一列可以/应该确定哪一行是V1,哪个V2等 - 可能是时间戳? - 您可以通过它来命令,而不是我使用的虚拟常数,它将不确定地分配递增的V值。

您可能还需要在表名前加dbo.作为问题。如果你需要在程序中执行此操作,只需将其包装为MTO说:

PROCEDURE find_duplicates IS
BEGIN
  merge into
  (
    select unique_id, rowid
    from dbo.Temp_Weekly_Export_File
  ) t
  using (
    select unique_id,
      row_number() over (partition by unique_id order by 1) as rnk,
      count(*) over (partition by unique_id) as cnt
    from dbo.Temp_Weekly_Export_File
  ) s
  on (s.rowid = t.rowid and s.cnt > 1)
  when matched then
  update set t.unique_id = s.unique_id ||'_V'||s.rnk;
END find_duplicates;

答案 1 :(得分:2)

正如Alex Poole所提到的,它正在更新所有三行,因为where条件没有区分行,因此你可以使用rowid来查找重复项并更新它们。

PROCEDURE find_duplicates 
  IS

      cursor c_duplicates is
        select UNIQUE_ID,rnk,rdfrom (
          select UNIQUE_ID
                ,rowid rd
                ,DENSE_RANK() OVER(PARTITION BY UNIQUE_ID ORDER BY rowid asc) rnk
                ,COUNT(*) OVER(PARTITION BY UNIQUE_ID) cnt              from dbo.Temp_Weekly_Export_File
           ) where cnt>1;
     c_duplicates_rec c_duplicates%ROWTYPE;    
    BEGIN
        open c_duplicates;
          LOOP
            FETCH c_duplicates into c_duplicates_rec;
             EXIT WHEN c_duplicates%NOTFOUND;

            UPDATE dbo.Temp_Weekly_Export_File
            SET UNIQUE_ID=c_duplicates_rec.UNIQUE_ID||'_V'||c_duplicates_rec.rnk
            where rowid=c_duplicates_rec.rd;
          END LOOP;
          CLOSE c_duplicates;
  EXCEPTION 
    WHEN OTHERS THEN 
    IF c_duplicates%ISOPEN THEN CLOSE c_duplicates; END IF;
     RAISE;
  END;

PS:我还没有测试过代码