我有一个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;
答案 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:我还没有测试过代码