CSDN-CSDN社区-MS-SQL Server-基础类

收藏 每个分类取5条, 这样的SQL如何写??[问题点数:100,结帖人:ghj1976]

  • ghj1976
  • (蝈蝈俊.net)
  • 等 级:
  • 结帖率:
  • 6

楼主发表于:2008-05-04 14:20:25
比如,假设我有这样的一个表 : table1

表的结构如下:

SQL code

CREATE TABLE table1
(
	[ID] [bigint] IDENTITY(1,1) NOT NULL,
	[Name] [nvarchar](128) NOT NULL,
	[class] int not null,
	[date] datetime not null
)



class 表示分类编号。 分类数不固定, 至少有上千种分类
date 表示该条记录被更新的时间

我现在想获得每个分类最新被更新的5条记录。

我该如何写写这个SQL 语句??


拼一个巨大的SQL 不太现实,因为分类太多了。

使用游标遍历每个分类,总觉得不是很好的方法。
谁有更好的方法呢??


回复次数:18
#1楼 得分:0回复于:2008-05-04 14:21:49
蝈蝈提问??
  • liangCK用户头像
  • liangCK
  • (小梁 爱 兰儿 (梁爱兰))
  • 等 级:
  • 2

    2

#2楼 得分:2回复于:2008-05-04 14:22:05
select *
from table1 a
where 5>(select count(*) from table1 where class=a.class and date>=a.date)
#3楼 得分:2回复于:2008-05-04 14:22:35
SQL code
select * from table1 as t where date in (select top 5 date from talbe1 where class=t.class order by date desc)
  • liangCK用户头像
  • liangCK
  • (小梁 爱 兰儿 (梁爱兰))
  • 等 级:
  • 2

    2

#4楼 得分:0回复于:2008-05-04 14:22:56
select *
from table1 a
where id in(select top 5 id from table1 where class=a.class order by date desc)
  • sdhylj用户头像
  • sdhylj
  • (青锋-SS)
  • 等 级:
  • 4

#5楼 得分:2回复于:2008-05-04 14:23:12
SQL code
--按某一字段分组取最大(小)值所在行的数据
(爱新觉罗.毓华 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
*/
--七,如果整行数据有重复,所有的列都相同。
/*
数据如下:
name val memo
a    2   a2(a的第二个值)
a    1   a1--a的第一个值
a    1   a1--a的第一个值
a    3   a3:a的第三个值
a    3   a3:a的第三个值
b    1   b1--b的第一个值
b    3   b3:b的第三个值
b    2   b2b2b2b2
b    4   b4b4
b    5   b5b5b5b5b5
*/
--在sql server 2000中只能用一个临时表来解决,生成一个自增列,先对val取最大或最小,然后再通过自增列来取数据。
--创建表并插入数据:
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',    1,   'a1--a的第一个值')
insert into tb values('a',    3,   'a3: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

select * , px = identity(int,1,1) into tmp from tb

select m.name,m.val,m.memo from
(
  select t.* from tmp t where val = (select min(val) from tmp where name = t.name)
) m where px = (select min(px) from
(
  select t.* from tmp t where val = (select min(val) from tmp where name = t.name)
) n where n.name = m.name)

drop table tb,tmp

/*
name       val         memo
---------- ----------- --------------------
a          1           a1--a的第一个值
b          1           b1--b的第一个值

(2 行受影响)
*/
--在sql server 2005中可以使用row_number函数,不需要使用临时表。
--创建表并插入数据:
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',    1,   'a1--a的第一个值')
insert into tb values('a',    3,   'a3: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

select m.name,m.val,m.memo from
(
  select * , px = row_number() over(order by name , val) from tb
) m where px = (select min(px) from
(
  select * , px = row_number() over(order by name , val) from tb
) n where n.name = m.name)

drop table tb

/*
name       val         memo
---------- ----------- --------------------
a          1           a1--a的第一个值
b          1           b1--b的第一个值

(2 行受影响)
*/
#6楼 得分:88回复于:2008-05-04 14:24:23
  • ghj1976用户头像
  • ghj1976
  • (蝈蝈俊.net)
  • 等 级:
  • 6

#7楼 得分:0回复于:2008-05-04 14:24:36
to Limpire:

where date in 

这个字段是时间字段,而且并不是唯一的,显然不行
#8楼 得分:2回复于:2008-05-04 14:26:06
SQL code
数据如下:
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分组取最小的两个(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
*/
  • ghj1976用户头像
  • ghj1976
  • (蝈蝈俊.net)
  • 等 级:
  • 6

#9楼 得分:0回复于:2008-05-04 14:31:45
这个表的数据量比较大。

前面几个方法, 都相当耗时间。 最快的是下面这个方法:

引用 6 楼 jinjazz 的回复:
SQL codeselectid,name,class,datefrom(selectid,name,class,date ,row_number()over(partitionbyclassorderbydatedesc)asrowindexfromtable1)awhererowindex <=5
  • ghj1976用户头像
  • ghj1976
  • (蝈蝈俊.net)
  • 等 级:
  • 6

#10楼 得分:0回复于:2008-05-04 14:33:06
还是 SQL 版活跃,

发出问题, 马上就很多回复
  • pt1314917用户头像
  • pt1314917
  • (背着灵魂漫步)
  • 等 级:
#11楼 得分:2回复于:2008-05-04 14:44:25
SQL code

CREATE TABLE table1
(
    [ID] [bigint] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](128) NOT NULL,
    [class] int not null,
    [date] datetime not null
)

----------------------
select * from table1 a where id in
(select top 5 id from table1 where class=a.class order by date desc)

#12楼 得分:2回复于:2008-05-04 14:45:16
引用 6 楼 jinjazz 的回复:
SQL codeselect id,name,class,date from(
select id,name,class,date ,row_number() over(partition by class order by date desc)
as rowindex from table1)a
where rowindex <=5
  • ghj1976用户头像
  • ghj1976
  • (蝈蝈俊.net)
  • 等 级:
  • 6

#13楼 得分:0回复于:2008-05-04 15:26:35
问题解决, 揭帖给分


由于 jinjazz  的方案性能最高, 他将获得 80 分。
剩下的 20 分平均分配给其他给出解决方案的人。


  • ghj1976用户头像
  • ghj1976
  • (蝈蝈俊.net)
  • 等 级:
  • 6

#14楼 得分:0回复于:2008-05-04 15:30:51
由于分数不好分,改分分策略如下:

jinjazz  一人获得 88 分。


其他6个人
liangCK
Limpire
sdhylj
kk19840210
pt1314917
dobear_0922

每人2分

非常感谢大家的帮忙。
#15楼 得分:0回复于:2008-05-08 15:59:38
强帖留名!
  • xocom用户头像
  • xocom
  • (肉球人)
  • 等 级:
#16楼 得分:0回复于:2008-06-14 13:53:41
MARK~
#17楼 得分:0回复于:2008-07-23 17:58:27
学习
#18楼 得分:0回复于:2008-08-03 22:56:43
学习 那位高手能给小弟 具体讲解下 为何 jinjazz 的 效率最高吗????
相关问题
高分求解答: 利用SQL语句取每个分类的前5条记录MS-SQL Server / 疑难 ...
怎样能用一句SQL语句从表中取不同分类的前两条Web 开发/ ASP - CSDN ...
怎样在Select 语句的每个分组中取前几位的记录? MS-SQL Server / 基础 ...
这样的sql怎么写? MS-SQL Server / 基础类- CSDN社区community.csdn.net
如何用一句sql语句选取分类及子分类的前5条产品.NET技术/ ASP.NET ...
怎样提出每组的前五个记录,如果该组记录少于5个,则有多少记录显示 ...