假设我有一个包含几亿行的表,看起来像这样:
memID | foo | bar | foobar
1 | blah | blah | blah
1 | blah | blah | blah
1 | blah | blah | blah
1 | blah | blah | blah
1 | blah | blah | blah
1 | blah | blah | blah
1 | blah | blah | blah
2 | blah | blah | blah
2 | blah | blah | blah
2 | blah | blah | blah
2 | blah | blah | blah
2 | blah | blah | blah
.
.
.
10001 | blah | blah | blah
10001 | blah | blah | blah
我需要一个查询,它将返回一系列成员ID中每个memID的前N行。 例如,如果N = 3且范围为0-2,则应返回
memID | foo | bar | foobar
1 | blah | blah | blah
1 | blah | blah | blah
1 | blah | blah | blah
2 | blah | blah | blah
2 | blah | blah | blah
2 | blah | blah | blah
我考虑过几种方法,首先创建一个大规模的
SELECT TOP (3) *
FROM table
WHERE memID = 0
UNION ALL
SELECT TOP (3) *
FROM table
WHERE memID = 1
.
.
.
在代码中查询。出于可能明显的原因,这不是一个真实的选择。
第二种方法是创建一个临时表并循环遍历memID的范围,将每个memID的TOP 3插入到该临时表中。
WHILE @MemID < 10000 AND @MemID > 0
BEGIN
INSERT INTO tmp_Table
SELECT TOP (3) *
FROM table
WHERE memID = @MemID
SET @MemID = @MemID + 1
END
这有效,但我想知道是否有一个更优雅的单一查询解决方案,我不知道。
Cadaeic给了我一个没有修补的答案,但是感谢所有提出分析的人,看起来我有一些认真的阅读。
答案 0 :(得分:5)
declare @startID int, @endID int, @rowsEach int
select @startID = 0, @endID = 2, @rowsEach = 3
select *
from
(
select memID, foo, bar, foobar, row_number() over (partition by dense_rank order by dense_rank) [rank_row]
from
(
select memID, foo, bar, foobar, dense_rank() over (order by memID) [dense_rank]
from #test
where memID between @startID and @endID
) a
) b
where rank_row <= @rowsEach
结果:
memID foo bar foobar rank_row
----------- ---- ---- ------ --------------------
1 blah blah blah 1
1 blah blah blah 2
1 blah blah blah 3
2 blah blah blah 1
2 blah blah blah 2
2 blah blah blah 3
如果你想在本地测试,这里是设置代码:
create table #test
(
memID int not null
, foo char(4) not null
, bar char(4) not null
, foobar char(4) not null
)
insert into #test (memID, foo, bar, foobar)
select 1, 'blah', 'blah', 'blah'
union all
select 1, 'blah', 'blah', 'blah'
union all
select 1, 'blah', 'blah', 'blah'
union all
select 1, 'blah', 'blah', 'blah'
union all
select 1, 'blah', 'blah', 'blah'
union all
select 1, 'blah', 'blah', 'blah'
union all
select 1, 'blah', 'blah', 'blah'
union all
select 2, 'blah', 'blah', 'blah'
union all
select 2, 'blah', 'blah', 'blah'
union all
select 2, 'blah', 'blah', 'blah'
union all
select 2, 'blah', 'blah', 'blah'
union all
select 10001, 'blah', 'blah', 'blah'
union all
select 10001, 'blah', 'blah', 'blah'
union all
select 10001, 'blah', 'blah', 'blah'
答案 1 :(得分:2)
SQL> select ename,sal,
2 row_number()
3 over (order by sal desc)rn,
4 rank()
5 over (order by sal desc)rnk,
6 dense_rank()
7 over (order by sal desc)drnk
8 from emp
9 order by sal desc
10 /
ENAME SAL RN RNK DRNK
----- ---- -- --- ----
KING 5000 1 1 1
FORD 3000 2 2 2
SCOTT 3000 3 2 2
JONES 2975 4 4 3
BLAKE 2850 5 5 4
CLARK 2450 6 6 5
答案 2 :(得分:1)
如果您使用的是SQL Server 2005或2008,则可能需要调查Ranking Functions
答案 3 :(得分:1)
使用分析。我没有测试过,但应该关闭:
SELECT memID, foo, bar, foobar
FROM (
SELECT memID, foo, bar, foobar,
RANK() OVER (PARTITION BY memID ORDER BY memID) AS 'nRank'
FROM table
WHERE memID BETWEEN 0 AND 2)
WHERE nRank <= 3
答案 4 :(得分:0)
SELECT * FROM Member m
Join ( Select TOP(3) * From Table Order By Table.Id) as t
On t.MemberId = m.MemberId
Where m BETWEEN 0 and 10000
应该做的伎俩