Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL查询,在一个ID范围内返回每个ID的前N行_Sql_Sql Server_Database_Optimization - Fatal编程技术网

SQL查询,在一个ID范围内返回每个ID的前N行

SQL查询,在一个ID范围内返回每个ID的前N行,sql,sql-server,database,optimization,Sql,Sql Server,Database,Optimization,假设我有一个包含数亿行的表,看起来像这样: 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 | bl

假设我有一个包含数亿行的表,看起来像这样:

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的前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给了我一个不需要修改的答案,但感谢所有建议分析的人,看起来我有一些严肃的阅读要做。

如果您使用的是SQL Server 2005或2008,您可能希望调查使用分析的原因。我没有测试这个,但应该很接近:

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
我们应该这样做

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
如果您想在本地进行测试,以下是设置代码:

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'

定义“顶部”。您需要指定一些条件,为这些条件选择具有给定id的行。编辑以使TOP是一个函数更清楚。是否有主键?这会让事情变得容易得多。@blogsdon:我不认为乔尔是这个意思。你根据什么标准判断哪一行在前三名,哪一行不在前三名?Top通常伴随着一个命令来定义顶部的内容。或者它更像是最多三个任意样本行?哦,我明白了,除了它们都需要相同的memID之外,没有其他标准。因此,是的,您对最多三个任意样本行的描述是正确的。这是有效的。感谢所有建议分析的人,我有很多阅读要做!为什么在每个内部查询中保留select子句?为什么不使用IN语句执行外部选择,在IN语句中运行只返回主键的内部查询呢?您也可以在主键上进行类似的连接。。。
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'