导航
  • 主页
  • 基础类
  • 应用实例
  • 新技术前沿

部分重复字段的问题

flyforlove 2007-11-29 10:39:49
前几天在这个帖子里问过这个问题。http://topic.csdn.net/u/20071126/18/b6bcc77e-6548-4fd2-884c-80fc7d27fdcd.html

由于没想清楚就匆忙结贴了。
实际上和我要的还是有出入的。

我先把问题和答案再贴一遍。

问题
-----------------------------------------------------
表中有三个字段
F1,F2,F3
记录之间F1和F2有可能重复,F3不会,
比如
F1 F2 F3
1 11 1
2 22 2
2 22 3
1 11 4
3 33 5

对于F1和F2重复的,我只想要一条,任何一条都可以。
比如结果为
1 11 1
2 22 2
3 33 5

如果用postgresql里的distinct on很好写,但是不知道标准的sql怎么写?不能用函数,不能用临时表,只有一条sql语句。
---------------------------------------------------------------------------------------

答案
----------------------------------------------------------
select f1,f2,max(f3) f3 from tb group by f1,f2
select f1,f2,min(f3) f3 from tb group by f1,f2
----------------------------------------------------------


由于我的问题没有问清楚,所以导致答案和需求有出入,实在抱歉。

我所举的例子,只有三个字段,不重复的字段只有一个,所以答案是没有问题的,但是实际上,我项目中所遇到的问题,不重复的字段并不是一个,而是多个,比如

F1 F2 F3 F4
1 11 1 4
2 22 2 3
2 22 3 2
1 11 4 1
3 33 5 5

这样的话,就不能使用
elect f1,f2,max(f3),max(f4) f3 from tb group by f1,f2
因为,虽然项目需求可以得到任何一条记录,但是前提是这些记录必须是同一行的记录,如果按照上面的写法,那么得到的F3,F4就有可能不是同一行的。

由于需要分页和排序,所以不能把记录都取出来再由程序处理。



...全文
47 点赞 收藏 10
写回复
10 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
-狙击手- 2007-12-07
select a.* 
from tb a
where not exists(select 1 from tb where f1 = a.f1 and f2 = a.f2 and f3 > a.f3)
回复
dawugui 2007-12-07
to 潇洒老乌龟

你说的这几种方法,哪个效率更高一些呢?

都差不多.相对来说 not exists好点.
回复
simple16 2007-12-07

楼主的意思应该是表里面除了有重复的两个字段外,还有其它的字段,而你是想取出没有重复字段的整条记录,是吧!!!
我刚好也遇到同样的问题,我试过了潇洒老乌龟的第一种方法还比较好,针对你的情况也就是:

select a.* from tb a where f3 = (select max(f3) from tb where f1 = a.f1 ) order by f1

max(f3)可以换成另外的条件来排序,比如按时间等等。
回复
dawugui 2007-11-29
--这样也行
select a.* from tb a where not exists(select 1 from tb where f1 = a.f1 and f2 = a.f2 and f3 > a.f3)
select a.* from tb a where not exists(select 1 from tb where f1 = a.f1 and f2 = a.f2 and f3 < a.f3)
回复
dawugui 2007-11-29
select a.* from tb a where f3 = (select max(f3) from tb where f1 = a.f1 and f2 = a.f2)
select a.* from tb a where f3 = (select min(f3) from tb where f1 = a.f1 and f2 = a.f2)
回复
dawugui 2007-11-29
--我这个不比官方的差,利用是一个分组,你是按两个分组,类推而已.
--按某一字段分组取最大(小)值所在行的数据(2007-10-23于浙江杭州)
/*
数据如下:
name val memo
a 2 a2(a的第二个值)
a 1 a1--a的第一个值
a 3 a3:a的第三个值
b 1 b1--b的第一个值
b 3 b3:b的第三个值
b 2 b2b2b2b2
b 4 b4b4
b 5 b5b5b5b5b5
*/
--创建表并插入数据:
create table tb(name varchar(10),val int,memo varchar(20))
insert into tb values('a', 2, 'a2(a的第二个值)')
insert into tb values('a', 1, 'a1--a的第一个值')
insert into tb values('a', 3, 'a3:a的第三个值')
insert into tb values('b', 1, 'b1--b的第一个值')
insert into tb values('b', 3, 'b3:b的第三个值')
insert into tb values('b', 2, 'b2b2b2b2')
insert into tb values('b', 4, 'b4b4')
insert into tb values('b', 5, 'b5b5b5b5b5')
go

--一、按name分组取val最大的值所在行的数据。
--方法1:
select a.* from tb a where val = (select max(val) from tb where name = a.name) order by a.name
--方法2:
select a.* from tb a where not exists(select 1 from tb where name = a.name and val > a.val)
--方法3:
select a.* from tb a,(select name,max(val) val from tb group by name) b where a.name = b.name and a.val = b.val order by a.name
--方法4:
select a.* from tb a inner join (select name , max(val) val from tb group by name) b on a.name = b.name and a.val = b.val order by a.name
--方法5
select a.* from tb a where 1 > (select count(*) from tb where name = a.name and val > a.val ) order by a.name
/*
name val memo
---------- ----------- --------------------
a 3 a3:a的第三个值
b 5 b5b5b5b5b5
*/

--二、按name分组取val最小的值所在行的数据。
--方法1:
select a.* from tb a where val = (select min(val) from tb where name = a.name) order by a.name
--方法2:
select a.* from tb a where not exists(select 1 from tb where name = a.name and val < a.val)
--方法3:
select a.* from tb a,(select name,min(val) val from tb group by name) b where a.name = b.name and a.val = b.val order by a.name
--方法4:
select a.* from tb a inner join (select name , min(val) val from tb group by name) b on a.name = b.name and a.val = b.val order by a.name
--方法5
select a.* from tb a where 1 > (select count(*) from tb where name = a.name and val < a.val) order by a.name
/*
name val memo
---------- ----------- --------------------
a 1 a1--a的第一个值
b 1 b1--b的第一个值
*/

--三、按name分组取第一次出现的行所在的数据。
select a.* from tb a where val = (select top 1 val from tb where name = a.name) order by a.name
/*
name val memo
---------- ----------- --------------------
a 2 a2(a的第二个值)
b 1 b1--b的第一个值
*/

--四、按name分组随机取一条数据。
select a.* from tb a where val = (select top 1 val from tb where name = a.name order by newid()) order by a.name
/*
name val memo
---------- ----------- --------------------
a 1 a1--a的第一个值
b 5 b5b5b5b5b5
*/

--五、按name分组取最小的两个(N个)val
select a.* from tb a where 2 > (select count(*) from tb where name = a.name and val < a.val ) order by a.name,a.val
select a.* from tb a where val in (select top 2 val from tb where name=a.name order by val) order by a.name,a.val
select a.* from tb a where exists (select count(*) from tb where name = a.name and val < a.val having Count(*) < 2) order by a.name
/*
name val memo
---------- ----------- --------------------
a 1 a1--a的第一个值
a 2 a2(a的第二个值)
b 1 b1--b的第一个值
b 2 b2b2b2b2
*/

--六、按name分组取最大的两个(N个)val
select a.* from tb a where 2 > (select count(*) from tb where name = a.name and val > a.val ) order by a.name,a.val
select a.* from tb a where val in (select top 2 val from tb where name=a.name order by val desc) order by a.name,a.val
select a.* from tb a where exists (select count(*) from tb where name = a.name and val > a.val having Count(*) < 2) order by a.name
/*
name val memo
---------- ----------- --------------------
a 2 a2(a的第二个值)
a 3 a3:a的第三个值
b 4 b4b4
b 5 b5b5b5b5b5
*/
回复
hui_hui_2007 2007-11-29
示例带有通用性。可以举一反三呀。
回复
wzy_love_sly 2007-11-29
那是要f3,还是f4,需要有个优先顺序
回复
hui_hui_2007 2007-11-29

以下网址是官方的解决方案

http://support.microsoft.com/kb/139444/zh-cn

以下是一个实例说明

--创建一个表,假设col1和col2两列的组合应该惟一,但是现在有重复键,我们的目的就是去除重复行
create table t1(
col1 int,
col2 int,
col3 char(50)
)

insert into t1
select 1, 1, 'data value 1' union all
select 1, 1, 'data value 1' union all
select 1, 1, 'data value 1' union all
select 1, 2, 'data value 2' union all
select 1, 3, 'data value 3-1' union all
select 1, 3, 'data value 3-2' union all
select 1, 3, 'data value 3-3' union all
select 1, 4, 'data value 4' union all
select 1, 5, 'data value 5' union all
select 1, 6, 'data value 6-1' union all
select 1, 6, 'data value 6-2' union all
select 1, 7, 'data value 7' union all
select 1, 8, 'data value 8'

--看一下表可以发现,(1,1),(1,3),(1,6)有重复
select * from t1

--选择重复的键值放入临时表中
SELECT col1, col2, col3=count(*)
INTO holdkey
FROM t1
GROUP BY col1, col2
HAVING count(*) > 1

--查看表holdkey
select * from holdkey

--结果如下,可知(1,1)重复行为3行,同理(1,3)为3行,(1,6)为2行
col1 col2 col3
----------- ----------- -----------
1 1 3
1 3 3
1 6 2

(所影响的行数为 3 行)

--选择重复的行放入临时表中,以清除进程中的重复值。例如:
SELECT DISTINCT a.*
INTO holddups
FROM t1 a inner join holdkey b
on (a.col1 = b.col1 AND a.col2 = b.col2)

--查看holddups表
select * from holddups

col1 col2 col3
----------- ----------- --------------------------------------------------
1 1 data value 1
1 3 data value 3-1
1 3 data value 3-2
1 3 data value 3-3
1 6 data value 6-1
1 6 data value 6-2

(所影响的行数为 6 行)

--查询是否存在键重复而行唯一的情况
SELECT col1, col2, count(*) as 行数
FROM holddups
GROUP BY col1, col2

--结果如下,可见(1,3),(1,6)都在键重复但是行惟一的情况
--因为行数列全为1才是正常的
col1 col2 行数
----------- ----------- -----------
1 1 1
1 3 3
1 6 2

(所影响的行数为 3 行)

--下面要修改holddubs表,将同一键值,但是第三列不同的情况删除。保证不同键值时行一定惟一
delete holddups
where col3 in
('data value 3-2','data value 3-3','data value 6-2')

--再查询holddups,看是否正常
select * from holddups

SELECT col1, col2, count(*) as 行数
FROM holddups
GROUP BY col1, col2

--结果为下,行数全为1,说明是正常的了
col1 col2 行数
----------- ----------- -----------
1 1 1
1 3 1
1 6 1

(所影响的行数为 3 行)

--从原始表中删除重复的行
DELETE t1
FROM t1, holdkey
WHERE t1.col1 = holdkey.col1
AND t1.col2 = holdkey.col2

--将惟一行放回原始表
INSERT t1 SELECT * FROM holddups

--查看原始表
select * from t1

--结果如下,可见重复键的列已没有了
col1 col2 col3
----------- ----------- --------------------------------------------------
1 1 data value 1
1 3 data value 3-1
1 6 data value 6-1
1 2 data value 2
1 4 data value 4
1 5 data value 5
1 7 data value 7
1 8 data value 8

(所影响的行数为 8 行)

回复
flyforlove 2007-11-29
to 潇洒老乌龟

你说的这几种方法,哪个效率更高一些呢?
回复
发动态
发帖子
MS-SQL Server
创建于2007-09-28

3.2w+

社区成员

MS-SQL Server相关内容讨论专区
申请成为版主
社区公告
暂无公告