2009-02-17 92 views
2

每個ID返回前N行可以說我有一個包含幾百萬行的表看起來是這樣的:SQL查詢來在一系列的ID

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

定義'頂部'。您需要指定某些標準,選擇具有給定標識的行。 – 2009-02-17 20:57:43

+0

編輯更清楚地表明TOP是一種功能。 – blogsdon 2009-02-17 21:08:03

回答

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 

而這裏的SET-如果您想在本地進行測試,請提供代碼:

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

使用分析。我沒有測試這一點,但應該接近:

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 
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 

應該做的伎倆

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