如何在SQL Server中实现LIMIT?


Answers:


127

启动SQL SERVER 2005,可以执行此操作...

USE AdventureWorks;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
    FROM Sales.SalesOrderHeader 
) 
SELECT * 
FROM OrderedOrders 
WHERE RowNumber BETWEEN 10 AND 20;

或类似版本的2000及以下版本...

SELECT TOP 10 * FROM (SELECT TOP 20 FROM Table ORDER BY Id) ORDER BY Id DESC

6
如果表中有14行,第二个查询将失败。它为您提供5至14行,但您希望获得11至14行。通常,结果的最后一个“页面”将失败,除非总行数是该“页面”大小的倍数。
比尔·卡文

147
MS再次需要把这样一个简单的事情变得如此困难!
马丁

下面是我在SQL Server Management Studio的2017年什么工作:SELECT * FROM [DBO] <插入表名的位置> WHERE @@ ROWCOUNT BETWEEN <插入分钟的位置>和<插入这里最大>
Artorias2718


58

笨拙,但可以使用。

SELECT TOP 10 * FROM table WHERE id NOT IN (SELECT TOP 10 id FROM table ORDER BY id) FROM table ORDER BY id

IMO忽略MSSQL的LIMIT子句。您不必执行这种笨拙的解决方法。


您还有其他建议可以绕过这个吗?
Bigballs'Mar

上次不得不处理MSSQL时,我做了很多谷歌搜索,这是我发现的最佳解决方案。不愉快,但是有效。
ceejayoz

仅当结果集包含唯一的列时,此解决方案才有效。这不是为任何查询模拟LIMIT的通用解决方案。
比尔·卡文

1
我现在处于类似的困境中……但是,就我而言,我被束之高阁……当所谓的“专家” dba决定某个表中不必要的唯一键时,这甚至更加犯罪。 ...甚至不要提到外键和约束的主题!
Andrew Rollings,2009年

这个问题是,它不能很好地处理WHERE子句...我将尝试使用临时表,因为它不适用于我。
讨厌的馅饼,

37

从SQL SERVER 2012开始,可以使用OFFSET FETCH子句:

USE AdventureWorks;
GO
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader 
ORDER BY SalesOrderID
    OFFSET 10 ROWS
    FETCH NEXT 10 ROWS ONLY;
GO

http://msdn.microsoft.com/zh-CN/library/ms188385(v=sql.110).aspx

当订购依据不是唯一时,这可能无法正常工作。

如果查询被修改为ORDER BY OrderDate,则返回的结果集与预期的不同。


使用“ with”仅需要一半的时间来完成查询-请参阅@Leon Tayson的答案。我不知道微软做了什么使它变慢。
isHuman

1
为什么这不是公认的答案?我们在2018年大声呐喊!
船长

1
@Skipper正确。被接受的仍然有效。让我们投票赞成这一点以反映更新。
克朗

18

这几乎是我十月份提出的一个问题的重复: 在Microsoft SQL Server 2000中模拟MySQL LIMIT子句

如果您使用的是Microsoft SQL Server 2000,则没有好的解决方案。大多数人不得不诉诸在具有IDENTITY主键的临时表中捕获查询结果。然后使用BETWEEN条件查询主键列。

如果您使用的是Microsoft SQL Server 2005或更高版本,则可以使用一个ROW_NUMBER()函数,因此可以获得相同的结果,但可以避免使用临时表。

SELECT t1.*
FROM (
    SELECT ROW_NUMBER OVER(ORDER BY id) AS row, t1.*
    FROM ( ...original SQL query... ) t1
) t2
WHERE t2.row BETWEEN @offset+1 AND @offset+@count;

您也可以将其编写为通用表表达式,如@Leon Tayson的答案中所示


ROW_NUMBER()OVER(ORDER BY)获得了在ANSI SQL:2003中有效的分数,尽管对除SQL Server之外的DBMS的支持非常有限。这当然很笨拙……
bobince

@bobince:事实证明Oracle,Microsoft SQL Server 2005,IBM DB2和PostgreSQL 8.4都支持窗口功能。那覆盖了绝大多数的SQL市场。仅当您使用MySQL,SQLite或上述数据库的旧版本时,支持才有缺陷。
Bill Karwin 2010年

16

这是我如何限制MS SQL Server 2012中的结果:

SELECT * 
FROM table1
ORDER BY columnName
  OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY

注意:OFFSET只能与或串联使用ORDER BY

解释代码行 OFFSET xx ROWS FETCH NEXT yy ROW ONLY

xx是你要开始从下表中,即拉动记录/行数:如果有40条记录在表1中,上面的代码将开始从第10行拉。

yy是你想从表中拉记录/行数。

以前面的示例为基础:如果表1有40条记录,并且您从第10行开始提取并获取NEXT集10(yy)。这意味着,上面的代码将从表1中的记录开始,从第10行开始,到第20行结束。因此,提取第10-20行。

查看链接以获取有关OFFSET的更多信息


12
SELECT  *
FROM    (
        SELECT  TOP 20
                t.*, ROW_NUMBER() OVER (ORDER BY field1) AS rn
        FROM    table1 t
        ORDER BY
                field1
        ) t
WHERE   rn > 10

好吧,我刚刚检查了一下,如果ORDER BY子句中有索引列,SQL Server证明足够聪明,可以在ROW_NUMBER()条件下停止。
Quassnoi

9

从语法上来说,MySQL LIMIT查询是这样的:

SELECT * FROM table LIMIT OFFSET, ROW_COUNT

可以将其翻译成Microsoft SQL Server,例如

SELECT * FROM 
(
    SELECT TOP #{OFFSET+ROW_COUNT} *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table
) a
WHERE rnum > OFFSET

现在,您的查询select * from table1 LIMIT 10,20将如下所示:

SELECT * FROM 
(
    SELECT TOP 30 *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rnum 
    FROM table1
) a
WHERE rnum > 10 

2

这是我尝试避免使用MS Server的原因之一...但无论如何。有时您只是没有选择(是!我必须使用过时的版本!)。

我的建议是创建一个虚拟表:

从:

SELECT * FROM table

至:

CREATE VIEW v_table AS    
    SELECT ROW_NUMBER() OVER (ORDER BY table_key) AS row,* FROM table

然后只需查询:

SELECT * FROM v_table WHERE row BETWEEN 10 AND 20

如果添加或删除字段,“行”将自动更新。

此选项的主要问题是ORDER BY是固定的。因此,如果您想要不同的顺序,则必须创建另一个视图。

更新

这种方法还有另一个问题:如果尝试过滤数据,它将无法按预期工作。例如,如果您这样做:

SELECT * FROM v_table WHERE field = 'test' AND row BETWEEN 10 AND 20

WHERE限制为位于10到20之间的行中的那些数据(而不是搜索整个数据集并限制输出)。


1

这是一种多步骤方法,将在SQL2000中起作用。

-- Create a temp table to hold the data
CREATE TABLE #foo(rowID int identity(1, 1), myOtherColumns)

INSERT INTO #foo (myColumns) SELECT myData order By MyCriteria

Select * FROM #foo where rowID > 10

1
SELECT 
    * 
FROM 
    (
        SELECT 
            top 20              -- ($a) number of records to show
            * 
        FROM
            (
                SELECT 
                    top 29      -- ($b) last record position
                    * 
                FROM 
                    table       -- replace this for table name (i.e. "Customer")
                ORDER BY 
                    2 ASC
            ) AS tbl1 
        ORDER BY 
            2 DESC
    ) AS tbl2 
ORDER BY 
    2 ASC;

-- Examples:

-- Show 5 records from position 5:
-- $a = 5;
-- $b = (5 + 5) - 1
-- $b = 9;

-- Show 10 records from position 4:
-- $a = 10;
-- $b = (10 + 4) - 1
-- $b = 13;

-- To calculate $b:
-- $b = ($a + position) - 1

-- For the present exercise we need to:
-- Show 20 records from position 10:
-- $a = 20;
-- $b = (20 + 10) - 1
-- $b = 29;

对我来说是一个很好的解决方案。
提德2014年

1

一定要试。在下面的查询中,您可以看到分组,排序,跳过行和限制行。

select emp_no , sum(salary_amount) from emp_salary
Group by emp_no 
ORDER BY emp_no 
OFFSET 5 ROWS       -- Skip first 5 
FETCH NEXT 10 ROWS ONLY; -- limit to retrieve next 10 row after skiping rows



0

如果您的ID是唯一标识符类型,或者表中的ID未排序,则必须执行以下操作。

select * from
(select ROW_NUMBER() OVER (ORDER BY (select 0)) AS RowNumber,* from table1) a
where a.RowNumber between 2 and 5



该代码将是

从限制2,5中选择*

0

最好在MSSQLExpress 2017中使用它。

SELECT * FROM
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) as [Count], * FROM table1
) as a
WHERE [Count] BETWEEN 10 and 20;

-给一列[Count]并为每一行分配一个唯一的计数而无需排序,然后再次选择可以提供限制的位置。::)


0

如下获得结果的一种可能方法,希望这会有所帮助。

declare @start int
declare @end int
SET @start = '5000';  -- 0 , 5000 ,
SET @end = '10000'; -- 5001, 10001
SELECT * FROM ( 
  SELECT TABLE_NAME,TABLE_TYPE, ROW_NUMBER() OVER (ORDER BY TABLE_NAME) as row FROM information_schema.tables
 ) a WHERE a.row > @start and a.row <= @end

0

简单的方法

MYSQL:

SELECT 'filds' FROM 'table' WHERE 'where' LIMIT 'offset','per_page'

MSSQL:

SELECT 'filds' FROM 'table' WHERE 'where' ORDER BY 'any' OFFSET 'offset' 
ROWS FETCH NEXT 'per_page' ROWS ONLY

ORDER BY是强制性的


-2

如果我没记错(自从使用SQL Server以来已经有一段时间了),您也许可以使用类似这样的命令:(2005年及以上)

SELECT
    *
   ,ROW_NUMBER() OVER(ORDER BY SomeFields) AS [RowNum]
FROM SomeTable
WHERE RowNum BETWEEN 10 AND 20

SQL Server 2012:消息207,级别16,状态1,行5无效的列名称'RowNum'。
e-info128 2013年

听起来您的某处陈述有错字。RowNum是我们分配给表达式的名称。将您的问题发布到消息源中,社区将为您提供帮助
Kris

这是无效的语法。您不能引用WHERE同一level SELECT子句中定义的别名。
ypercubeᵀᴹ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.