我们可以在不使用Pseudo coloumn rowid
的情况下删除重复记录吗...
删除重复记录时,max(rowid)/ min(rowid)的含义是什么?
答案 0 :(得分:0)
ROWID
是Oracle用于查找物理记录的内部行标识符。因此,即使您的" ID"可能有重复的值,但每条记录ROWID仍然是唯一的。
create table prices(
id varchar2(15) not null
,price number not null
,upd_date date not null
-- ,primary key(id)
);
ROWID ID PRICE UPD_DATE
------------------ -- ----- ----------
AChTgbADaAAFgxYAAA A 7 2018-04-10
AChTgbADaAAFgxYAAB B 8 2018-04-09
AChTgbADaAAFgxYAAC B 8 2018-04-09
AChTgbADaAAFgxYAAD B 8 2018-04-09
AChTgbADaAAFgxYAAE C 9 2018-04-06
AChTgbADaAAFgxYAAF C 8 2018-04-05
AChTgbADaAAFgxYAAG C 7 2018-04-04
组中的MAX(rowid)通常最近插入的记录,但这种假设在生产代码中经常出错。只能依赖于删除完美复制。完美的副本是select distinct *
导致一条记录的副本。对于所有其他用途,您需要鉴别器。可以使用鉴别器列来区分两个记录,例如具有指示修改时间的更新日期。
如果使用典型的ROWID方法重复删除我的示例表,则会错误地删除最近的价格9(由upd_date证明)。
delete
from prices
where rowid not in(
select max(rowid)
from prices
group by id);
更好的方法是首先使用鉴别器,然后最后使用ROWID。
delete
from prices
where rowid in(
select rid
from (select rowid as rid
,row_number() over( -- Assign a sequence number
partition by id -- Group rows by ID
order by upd_date desc -- Sort them by upd_date first
,rowid desc -- Then by ROWID
) as rn
from prices
)
-- The most recent record will be rn = 1.
-- The second most recent record will be rn = 2, etcetera
where rn > 1 -- Select only the duplicates ("after" the most recent one record
);
答案 1 :(得分:0)
如果整个行都是重复的,并且您希望删除除一个副本以外的所有行,则SQL中没有简单的方法可以选择要删除的行而不使用系统生成的行地址。
以Ronnis'PRICES
表为例,我们发现B
有三行完全重复:
ID PRICE UPD_DATE
-- ----- -----------
A 7 10/04/2018
B 8 09/04/2018
B 8 09/04/2018
B 8 09/04/2018
C 7 04/04/2018
C 8 05/04/2018
C 9 06/04/2018
虽然我们可能会使用像
这样的东西delete prices where id = 'B' and rownum <= 2;
这不是一个好的解决方案,因为我们必须知道ID和计数,并一次应用于一个ID。
我们可以删除它们而无需使用PL / SQL显式指定rowid:
declare
cursor c_prices is
select id, price
, row_number() over (partition by id order by upd_date desc) as seq
from prices
for update;
begin
for r in c_prices
loop
if r.seq > 1 then
delete prices where current of c_prices;
end if;
end loop;
end;
虽然当然内部where current of
语法正在使用rowid。
显式使用rowid使这更加简单:
delete prices where rowid in
( select lag(rowid) over (partition by id order by upd_date) from prices );
按日期顺序查找所有“之前”的rowid,并删除相应的行。每个集合中的最后一行不会出现在该列表中,因此不会被删除。