如何删除数据库中的冗余数据(2)
它将冗余数据选择到一个游标中并根据(LastNameFirstName)来分组(在我们这个方案中)然后打开游标然后循环地取出每一行然后用与先前的取出的键值进行比较如果这是第一次取出这个值或者这个值不是冗余键那么跳过这个记录然后取下一个不然的话这就是这个组中的冗余记录所以删掉它.
让我们运行一下这个存储过程
BEGIN
DeleteDuplicates;
END;
/
SELECTLastNameFirstNameCOUNT(*)
FROMCustomers
GROUPBYLastNameFirstName
HAVINGCOUNT(*)>;
最后一个查询语句没有返回值所以冗余数据没有了从表中取冗余数据的过程完全是由定义在csr_Duplicates这个游标中的SQL语句来实现的PL/SQl只是用来实现删除冗余数那么能不能完全用SQL语句来实现呢?
二.SQL解决方案使用RANK()删除冗余数据Oraclei分析函数RANK()来枚举每一个组中的元素在我们的方案中 我们应用这个方案我们使用这个函数动态的把冗余数据连续的排列起来加上编号组由Partintion by 这个语句来分开然后用Order by 进行分组SELECTIDLastNameFirstNameRANK()OVER(PARTITIONBYLastName
FirstNameORDERBYID)SeqNumber
FROMCustomers
ORDERBYLastNameFirstName;
SQL
ListingOutputofsingleSQLstatementthatusesRANK()
显示的是根据记录的条数的个数来显示尤其对于冗余数据
IDLASTNAMEFIRSTNAMESEQNUMBER
BlakeBecky
BlueDon
BradleyTom
ChangJim
GriffithDavid
HillLarry
KingChuck
KriegerJeff
KriegerJeff
KriegerJeff
LoneyJulie
LordDon
MasonPaul
MonroeJohn
SimonMichael
SimonMichael
StoneTony
StoneTony
StoneTony
StoneTony
StoneTony
我们可以看一到SeqNumber这一列中的数值冗余数据是根据ID号由小到大进行的排序所有的冗余数据的SqlNumber都大于一所有的非冗余数据都等于一所以我们取自己所需删除那么没用的SELECTIDLastNameFirstName
FROM
(SELECTIDLastNameFirstNameRANK()OVER(PARTITIONBYLastName
FirstNameORDERBYID)ASSeqNumber
FROMCustomers)
WHERESeqNumber>;
SQL
Listing冗余键的键值
有七行必须被删除
IDLASTNAMEFIRSTNAME
KriegerJeff
KriegerJeff
SimonMichael
StoneTony
StoneTony
StoneTony
StoneTony
rowsselected这显示有七行需要删除还是用上一个表我测试了一下这个代码它用了77秒种就删除了所有的数据准备好了用Sql语句来删除冗余数据版本一它执行了秒
DELETE
FROMCUSTOMERS
WHEREIDIN
(SELECTID
FROM
(SELECTIDLastNameFirstNameRANK()OVER(PARTITIONBYLastName
FirstNameORDERBYID)ASSeqNumber
FROMCustomers)
WHERESeqNumber>);
我们可以看到最后的两行语句对表中的数据进行了排序这不是有效的所以我们来优化一下最后一个查询语句把Rank()函数应用到只含有冗余数据的组而不是所有的列下面这个语句是比较有效率的虽然它不像上一个查询那样精简SELECTIDLastNameFirstName
FROM
(SELECTIDLastNameFirstNameRANK()OVER(PARTITIONBYLastName
FirstNameORDERBYID)ASSeqNumber
FROM
(SELECTIDLastNameFirstName
FROMCustomers
WHERE(LastNameFirstName)IN(SELECTLastNameFirstName
FROMCustomers
GROUPBYLastNameFirstName
HAVINGCOUNT(*)>)))
WHERESeqNumber>;
选择冗余数据只用了26秒钟这样就提高了%的性能这样就提高了将这个作为子查询的删除查询的效率
DELETE
FROMCustomers
WHEREIDIN
(SELECTID
FROM
(SELECTIDLastNameFirstNameRANK()OVER(PARTITIONBYLastName
FirstNameORDERBYID)ASSeqNumber
FROM
(SELECTIDLastNameFirstName
FROMCustomers
WHERE(LastNameFirstName)IN(SELECTLastNameFirstName
FROMCustomers
GROUPBYLastNameFirstName
HAVINGCOUNT(*)>)))
WHERESeqNumber>);
现在只用了秒钟的就完成的上面的任务比起上一个秒这是一个很大的进步相比之下存储过程用了秒这样存储过程有些慢了使用PL/SQL语句我们和我们以上的代码会得到更好的更精确的代码和提高你代码的执行效率虽然对于从数据库中枚举数据PL/SQL对于Sql两者没有什么差别但是对于数据的比较上PL/SQL就比SQL要快很多但是如果冗余数据量比较小的话我们尽量使用SQL而不使用PL/SQL如果你的数据表没有主键的话那么你可以参考其它技术
Rank()其它的方法
使用Rank()函数你可以对选择你所保留的数据(或者是小ID的或者是大ID 的就由RECDate这个列来决定这种情况下你可以把REcdate加入到(Orderby )子句中倒序或者正序
这是一种保留最大Id的一种解决方案
DELETE
FROMCustomers
WHEREIDIN
(SELECTID
FROM
(SELECTIDLastNameFirstNameRANK()OVER(PARTITIONBYLastNameFirstNameORDERBYRecDateDESCID)ASSeqNumber
FROM
(SELECTIDLastNameFirstNameRecDate
FROMCustomers
WHERE(LastNameFirstName)IN(SELECTLastNameFirstName
FROMCustomers
GROUPBYLastNameFirstName
HAVINGCOUNT(*)>)))
WHERESeqNumber>);
这种技术保证了你可以控制每一个表中的保留的组假设你有一个数据库有一个促销或者有一个折扣信息比如一个团体可以使用这种促销5次或者个人可以使用这个折扣三次为了指出要保留的组的个数你可以在where和having子句中进行设置那么你将删除所有大于你
设置有数的冗余组
DELETE
FROMCustomers
WHEREIDIN
(SELECTID
FROM
(SELECTIDLastNameFirstNameRANK()OVER(PARTITIONBYLastName
FirstNameORDERBYID)ASSeqNumber
FROM
(SELECTIDLastNameFirstName
FROMCustomers
WHERE(LastNameFirstName)IN(SELECTLastNameFirstName
FROMCustomers
GROUPBYLastNameFirstName
HAVINGCOUNT(*)>)))
WHERESeqNumber>);
AsyoucanseeusingtheRANK()functionallowsyoutoeliminateduplicatesina
singleSQLstatementandgivesyoumorecapabilitiesbyextendingthepowerof
your
queries
lishixinzhi/Article/program/Oracle/201311/18979
免责声明:本站发布的教育资讯(图片、视频和文字)以本站原创、转载和分享为主,文章观点不代表本网站立场。
如果本文侵犯了您的权益,请联系底部站长邮箱进行举报反馈,一经查实,我们将在第一时间处理,感谢您对本站的关注!
新励学网教育平台
海量全面 · 详细解读 · 快捷可靠
累积科普文章数:18,862,126篇