找回密码
 FreeOZ用户注册
查看: 2608|回复: 20
打印 上一主题 下一主题

[数据库] 如何按着优先级字段查重某一字段

[复制链接]
跳转到指定楼层
1#
发表于 14-7-2009 23:28:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
提示: 作者被禁止或删除, 无法发言

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?FreeOZ用户注册

x
要求:表中有重复的Account_NO,要求按着 Priority的优先级大小查重。

我目前解决了有主键的表的按优先级查重,对于没有主键的表,怎么更新,我还没找到办法。大家看看怎么好?

Table: ID (主键,自增长字段), Account_NO (有重复记录字段), Priority (排序优先级字段), DuplicatedFlag (标记字段), Other Fields

显示重复记录
SELECT * FROM Table
WHERE ID IN
(SELECT ID
FROM
(SELECT Row_Number() OVER (Account_NO DESC, Priority DESC, ID DESC) AS RowID, * FROM Table) A,
(SELECT Row_Number() OVER (Account_NO DESC, Priority DESC, ID DESC) AS RowID, * FROM Table) B
WHERE A.RowID > B.RowID
AND A.Account_NO = B.Account_NO
AND A.Priority >= B.Priority)

更新重复记录标记
UPDATE Table
SET DuplicatedFlag = 1
WHERE ID IN
(SELECT ID
FROM
(SELECT Row_Number() OVER (Account_NO DESC, Priority DESC, ID DESC) AS RowID, * FROM Table) A,
(SELECT Row_Number() OVER (Account_NO DESC, Priority DESC, ID DESC) AS RowID, * FROM Table) B
WHERE A.RowID > B.RowID
AND A.Account_NO = B.Account_NO
AND A.Priority >= B.Priority)

删除重复记录
DELETE Table
WHERE ID IN
(SELECT ID
FROM
(SELECT Row_Number() OVER (Account_NO DESC, Priority DESC, ID DESC) AS RowID, * FROM Table) A,
(SELECT Row_Number() OVER (Account_NO DESC, Priority DESC, ID DESC) AS RowID, * FROM Table) B
WHERE A.RowID > B.RowID
AND A.Account_NO = B.Account_NO
AND A.Priority >= B.Priority)
回复  

使用道具 举报

2#
发表于 15-7-2009 11:46:54 | 只看该作者
。。。。。。。。。。
一看你的SQL就晕,那么多嵌套,效率低。。。。。。。。。。。。

还有你的中文俺也看不懂
回复  

使用道具 举报

3#
发表于 15-7-2009 13:40:01 | 只看该作者

回复 #2 lufumin1832 的帖子

看着“查重”,在看着xblues的头像,就想到了“查虫”

评分

参与人数 1威望 +20 收起 理由
MillerYang + 20 你太有才了!

查看全部评分

回复  

使用道具 举报

4#
发表于 15-7-2009 13:45:36 | 只看该作者
  1. SELECT  *
  2.   FROM  Table
  3. WHERE  Account_NO
  4.    IN   (  SELECT Account_NO
  5.              FROM Table
  6.          GROUP BY Account_NO
  7.            HAVING COUNT(*)>1);
复制代码
回复  

使用道具 举报

5#
发表于 15-7-2009 17:21:46 | 只看该作者
回复  

使用道具 举报

6#
发表于 16-7-2009 00:10:04 | 只看该作者
应该是查重复,楼主少打了个“复”字。
一个group by + having就搞定了。4#的正解,另外再加个order by Priority就是楼主要的。
回复  

使用道具 举报

7#
 楼主| 发表于 16-7-2009 00:12:35 | 只看该作者

回复 #4 coredump 的帖子

提示: 作者被禁止或删除, 无法发言
你那个是简单查重,仔细看题目,这个是需要按某一字段为优先级来查重的。
回复  

使用道具 举报

8#
 楼主| 发表于 16-7-2009 00:18:01 | 只看该作者

回复 #6 sonybp 的帖子

提示: 作者被禁止或删除, 无法发言
你那种方法也可以的,但是我需要的不是删除重复记录,或者重新生成一个表,而是更新那个重复标记的字段,
如果本记录是重复记录,就更新标记字段为1。
回复  

使用道具 举报

9#
发表于 16-7-2009 00:29:57 | 只看该作者

回复 #8 xblues 的帖子

我没给出任何方法......
我只是说4楼的方法是对的。4楼的语句就抓出来了所有Account_NO有重复的记录。你再根据这些记录排序。把Priority最高的那条记录标记为1,然后删除其他的记录。
4楼的查询完全和有没有主键无关。

有点晚了,先睡了。如果还是不行,你留贴,我明天回你。
回复  

使用道具 举报

10#
发表于 16-7-2009 00:57:08 | 只看该作者
虫虫你准备写本SQL Cookbook么?
回复  

使用道具 举报

11#
发表于 16-7-2009 10:19:12 | 只看该作者

回复 #10 ritz 的帖子

他在写cook bug
回复  

使用道具 举报

12#
发表于 16-7-2009 10:20:59 | 只看该作者
原帖由 xblues 于 16-7-2009 00:12 发表
你那个是简单查重,仔细看题目,这个是需要按某一字段为优先级来查重的。


我给你的是关键的一句,剩下的都是添枝加叶的东西,自由发挥了,你第一楼的SQL语句问题最严重的就是差重复的子句,所以单独给你拿出来
回复  

使用道具 举报

13#
 楼主| 发表于 16-7-2009 23:03:00 | 只看该作者

回复 #12 coredump 的帖子

提示: 作者被禁止或删除, 无法发言
回复  

使用道具 举报

14#
发表于 24-7-2009 17:33:43 | 只看该作者
oracle 数据库可以有rowid字段标识列的, ms sql 和mysql 没有。
感慨一下, oralce 卖那么贵是有道理的。
回复  

使用道具 举报

15#
发表于 24-7-2009 17:49:13 | 只看该作者
原帖由 bfox 于 24-7-2009 17:33 发表
oracle 数据库可以有rowid字段标识列的, ms sql 和mysql 没有。
感慨一下, oralce 卖那么贵是有道理的。

ms sql中有 ROWGUIDCOL可以用,概念上和Oracle rowid是一致的。

评分

参与人数 1威望 +20 收起 理由
bfox + 20 看来是我对ms sql 用的不够深入,学习了。

查看全部评分

回复  

使用道具 举报

16#
 楼主| 发表于 25-7-2009 01:53:43 | 只看该作者

回复 #15 coredump 的帖子

提示: 作者被禁止或删除, 无法发言
那我上面的row number 不是一样么?
回复  

使用道具 举报

17#
发表于 25-7-2009 14:53:12 | 只看该作者

回复 #16 xblues 的帖子

row_number()受搜索结果影响,同一条数据库记录在不同的SQL语句的结果里Row_Number()是不一样的,同一SQL结果集的不同排序,聚合也会导致Row_Number()不一样。Rowid和那个ROWGUIDCOL相当于记录的物理地址,这个是不会变的,Rowid在同一数据库中唯一, ROWGUIDCOL则是GUID,全球唯一

评分

参与人数 1威望 +30 收起 理由
xblues + 30 谢谢分享!

查看全部评分

回复  

使用道具 举报

18#
发表于 23-9-2009 15:24:16 | 只看该作者
coredump的方法是正解,不过使用Rowid还是有些地方要注意,表的move、shrink等操作会造成Rowid的改变,这也是使用PK的原因之一。

评分

参与人数 1威望 +49 收起 理由
xblues + 49 谢谢分享!

查看全部评分

回复  

使用道具 举报

19#
发表于 23-9-2009 22:21:58 | 只看该作者
原帖由 bfox 于 24-7-2009 17:33 发表
oracle 数据库可以有rowid字段标识列的, ms sql 和mysql 没有。
感慨一下, oralce 卖那么贵是有道理的。

如果大家了解了ORACLE和MSSQL 还有DB2的体系架构,我只能说MSSQL和DB2都是玩具。DB2在银行里面有点搞头市场那是历史的原因,还有IBM的硬件和AIX的帮助。ORACLE单挑DB2的话,DB2连ORACLE 1/10的市场都拿不到。现在DB2的价格比ORACLE便宜了不知道多少。。。。。。
我对DB2也有一定了解,也是DB2的管理员。

[ 本帖最后由 maqianyi 于 23-9-2009 22:23 编辑 ]
回复  

使用道具 举报

20#
发表于 24-9-2009 13:36:35 | 只看该作者
原帖由 maqianyi 于 23-9-2009 22:21 发表

如果大家了解了ORACLE和MSSQL 还有DB2的体系架构,我只能说MSSQL和DB2都是玩具。DB2在银行里面有点搞头市场那是历史的原因,还有IBM的硬件和AIX的帮助。ORACLE单挑DB2的话,DB2连ORACLE 1/10的市场都拿不到。现在D ...

我不是很了解ORACLE,但我只能说,各家都有它的优点。要说玩具,IT有哪样技术不是玩具?当年叱诧风云的PDP-1到如今不也就成了博物馆的玩具?高手给他一个SQLite(甚至什么都不给,直接定义数据文件结构)就可以搞大型应用了。
回复  

使用道具 举报

21#
 楼主| 发表于 8-7-2010 03:34:31 | 只看该作者

今天又重新研究了一下这个查重的问题,我觉得还是我的方法好

提示: 作者被禁止或删除, 无法发言
改进一下,两步走。

表结构
ID    Name   City   Balance

问题
表中有重复ID,其他字段比如Name City Balance的值有可能一样,也有可能不一样。
如果所有字段的值都一样,你只要简单的运用 SELECT DISTINCT * FROM table 就可以了。

判断是否有重复行的方法有两种,先看第一种方法,也就是老乞丐上面已经提到的,用 GROUP HAVING
SELECT * FROM table WHERE ID IN (
SELECT ID FROM table GROUP BY ID HAVING COUNT(ID)>1)



我的方法如下,这个方法需要借助ROW_NUMBER()函数,先生成一个行号,再把带有行号的结果存储在一个临时表中,然后再临时表中根据行号进行删除操作,然后再用SELECT语句重新选出数据的同时去掉行号。

SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY NAME) AS ROWID, * INTO newtable FROM table

这样生成了一个新表,结构和原来的表几乎一样,只不过增加了一个叫做ROWID的字段,因为我是按着ID来PARTITION的,所以具体数据如下:

ROWID    ID    Name ........
1       1001   Lee
2       1001   Lee
3       1001   Wang
1       1003   Feng
2       1003   Feng
1       1002   Zhang

然后我就可以执行删除操作了
DELETE FROM newtable WHERE ROWID > 1

剩下的就是ROWID=1的非重复记录了,直接用一条SELECT语句还原字段就好啦
SELECT ID, Name, Balance INTO finaltable FROM newtable

这个方法的好处是利用ROW_NUMBER函数,这个函数功能相当强大了,支持任何方式的分区排序,所以可以对各种查重有针对性的操作。
回复  

使用道具 举报

您需要登录后才可以回帖 登录 | FreeOZ用户注册

本版积分规则

小黑屋|手机版|Archiver|FreeOZ论坛

GMT+10, 25-4-2024 03:54 , Processed in 0.061969 second(s), 37 queries , Gzip On, Redis On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表