SQL Server如何选择前10-20个结果?

28

我有两列数据,第一列我想要显示前10个产品(1-10)

就是这样

SELECT TOP 10 * FROM Product   

我希望在第二列显示接下来的10个结果(11-20)。

如何做到?


1
请问使用的 SQL Server 版本是哪个? - Martin Smith
使用哪个平台,MySql 还是 SQLServer? - Hogan
5
在SQL Server 2011(代号“Denali”)中,您将能够执行SELECT * FROM Table ORDER BY Something OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY,这非常棒 :) - Alex Bagnolini
1
@AlexBagnolini,你能把那个作为答案吗?因为现在它确实是更正确的答案了。如果不是答案,人们可能会在评论中错过它。 - monty
1
@MartinSmith 确实,5年后重新阅读这些问题,我也能看出来 :) - monty
显示剩余2条评论
16个回答

31
WITH T AS
(
SELECT TOP 20 name, 
       row_number() OVER (ORDER BY id) AS RN
FROM Products
ORDER BY id
)
SELECT 
       MAX(CASE WHEN RN <=10 THEN name END) AS Col1,
       MAX(CASE WHEN RN > 10 THEN name END) AS Col2
FROM T       
GROUP BY RN % 10

3
我必须承认我很喜欢阅读Martin和Marc的解决方案。对两位都点赞。 - niktrs
3
+1 真是太聪明了,而且对执行计划的影响也比我的解决方案小得多 - 恭喜! - marc_s
1
@marc_s 这就是我的意思,我喜欢阅读。不同的方法和解决方案让我(至少)以更好的方式思考 :) - niktrs
@niktrs:确实 - 我也喜欢看到其他(非常聪明!)人的解决方案 - 这有助于我每天提高自己的技能! :-) (而Martin在这里肯定是顶级的SQL大师之一 - 已经救了我的几次危机 :-) 谢谢Martin!) - marc_s
谢谢您的提振自信的评论! - Martin Smith

14

我会这样做:

SELECT [columns] FROM [table names] ORDER BY [column name] DESC LIMIT 10 OFFSET 10;

这更为简单且不那么复杂....

你们觉得呢?


2
它似乎在SQL Server上无法工作,但是如果将LIMIT 10 OFFSET 10替换为OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;,那么它将在SQL Server上工作。 - Eugene

9
select top 10 wwwhid from wwwh  where wwwhid not in(select top 10 wwwhid from wwwh)

聪明敏锐 - Khurram Shaikh
@KhurramShaikh 谢谢 - senthilkumar2185

5

从SQL Server 2012开始,引入了ORDER BY OFFSET/FETCH功能:

SELECT *
FROM SomeTable
ORDER BY someIdField 
    OFFSET 10 ROWS
    FETCH NEXT 10 ROWS ONLY;

4

在SQL Server中,要完成这个任务有点棘手。如果你使用的是SQL Server 2005或更高版本,可以使用一个CTE和一些巧妙的技巧来实现所需的结果:

;WITH TopProducts AS
(
    SELECT 
        ProductID, ProductName,
        ROW_NUMBER() OVER(ORDER BY --some-column-here-- DESC) 'RN'
    FROM dbo.Products
)
SELECT 
    p1.ProductID, p1.ProductName,
    p2.ProductID, p2.ProductName
FROM 
    TopProducts p1
CROSS JOIN 
    TopProducts p2
WHERE 
    p1.RN BETWEEN 1 AND 10        -- get rows 1-10 from the first CTE
    -- AND p2.RN BETWEEN 11 AND 20   redundant, as niktrs pointed out
    AND p1.RN + 10 = p2.RN        -- join rows from P1 and P2 so you don't get a cartesian product
CTE(公共表达式)对产品进行编号 - 这需要基于您的Products表中的某些列,但您没有提及哪个列定义了顺序。 然后,我们从CTE中选择第1-10行,以及从第二个CTE的第11-20行。如果您将其保留不变,您将获得100行 - 第一个结果集的1-10行与第二个结果集的每个10行的组合。 这就是为什么您需要基于行号的附加条件来“连接”每个结果集中的一行,因此您将获得十行 - 第一列具有来自Products表的项目1-10,第二列具有第11-20行。

1
虽然我认为这个代码比我的代码表现更好,在我的测试环境中却进行了两次索引扫描而不是索引搜索?此外,我认为“AND p2.RN BETWEEN 11 AND 20”是多余的,因为“AND p1.RN + 10 = p2.RN”。 - niktrs
1
@niktrs:你说的冗余是对的 - 甚至可以将其写成INNER JOIN,并将p1.RN = p2.RN - 10作为JOIN条件 - 这也可以工作。 - marc_s
@marc_s:从逻辑上讲,我认为这是一个内连接。无论如何,加1,它做得很好。 - Andriy M

2

我不确定这是最好的方法,但它可以运作。

select *
from
(
SELECT top 10 ROW_NUMBER() OVER(ORDER BY product) linenum, product
FROM products
) t1
 JOIN 
(
SELECT top 20 ROW_NUMBER() OVER(ORDER BY product) linenum, product
FROM products
) t2 ON t1.linenum+10 = t2.linenum

我认为这将导致前10行在两列中重复显示,一次是单独显示,一次与其他10行一起显示。也许你的意思是使用INNER JOIN而不是FULL JOIN?或者我有什么遗漏吗? - Andriy M

2
declare @FromRange int
declare @ToRange int
set @FromRange =11
set @ToRange =20
SELECT top(@ToRange-@FromRange+1) * FROM [tbl] 
where tbl_id not in (select top (@FromRange-1) tbl_id from tbl)
ORDER BY tbl_id 

对我来说这是最好的答案。非常感谢。 - Nisha
第二个查询也需要使用“按tbl_id排序”的语句,因此需要选择从顶部开始的(@FromRange-1)个tbl_id。 - SoulRayder

1
WITH result_set AS 
    (SELECT ROW_NUMBER() OVER 
        (ORDER BY Product.ID DESC) AS 
     [row_number], Product.intId AS id, Product.Title As Title
     FROM Product WHERE Product.Price > 11)
SELECT * FROM result_set WHERE [row_number] BETWEEN 10 AND 19 

1
SELECT * FROM Product LIMIT(10,10)

12
SQL Server 没有 LIMIT 关键字。 - Martin Smith
4
没有任何一版 SQL Server 支持LIMIT关键字,这是 MySQL 的自定义特性,不是任何标准。 - marc_s

1

试试这个:

SELECT * 
FROM 
( 
    SELECT TOP 10 ROW_NUMBER() OVER(ORDER BY ColName) RowNo, ColName
    FROM TableName 
) table1 
INNER JOIN  
( 
    SELECT TOP 20 ROW_NUMBER() OVER(ORDER BY ColName) RowNo, ColName 
    FROM TableName 
) table2 ON table1.RowNo + 10 = table2.RowNo 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,