如何使用 SQL Server 实现 LIMIT? [复制]

Posted

技术标签:

【中文标题】如何使用 SQL Server 实现 LIMIT? [复制]【英文标题】:How to implement LIMIT with SQL Server? [duplicate] 【发布时间】:2010-10-10 20:43:20 【问题描述】:

我对 mysql 进行了以下查询:

select * from table1 LIMIT 10,20

如何使用 SQL Server 做到这一点?

【问题讨论】:

既然这个问题是先问的,那其他问题不会是重复的吗? 见:Should I flag a question as duplicate if it has received better answers? @Bigballs 自 2012 年以来接受的答案是错误的并且效率极低 【参考方案1】:
SELECT TOP 10 * FROM table;

是一样的

SELECT * FROM table LIMIT 0,10;

Here's an article about implementing Limit in MsSQL 读起来不错,尤其是 cmets。

【讨论】:

谢谢,但是我想要10到20之间的记录,有办法吗? 这个答案不回应原始问题,但如果像我这样的人需要知道如何获得前 N 个结果并通过谷歌等到达这里,这很有用...【参考方案2】:

笨拙,但它会工作。

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

MSSQL 省略 LIMIT 子句是犯罪行为,IMO。你不应该做这种笨拙的解决方法。

【讨论】:

你有其他建议绕过这个吗? 上次我不得不处理 MSSQL 时做了很多谷歌搜索,这是我找到的最佳解决方案。不愉快,但它有效。 此解决方案仅在结果集包含唯一列时才有效。这不是为任何查询模拟 LIMIT 的通用解决方案。 我现在也处于类似的困境中......但是,在我的情况下,我被水洗了......当所谓的“专家”dba 决定不必要的唯一密钥时,这更加犯罪在一个表中...任何表...甚至不要提出外键和约束的主题! 这个问题是,它不能很好地处理 WHERE 子句...我要试试临时表,因为它不适合我。【参考方案3】:

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

【讨论】:

如果您有第二次查询失败,例如表中有 14 行。它为您提供第 5 到第 14 行,但您需要第 11 到第 14 行。通常,结果的最后一个“页面”会失败,除非总行数是该“页面”大小的倍数。 这么简单的事情,又要被MS搞得这么难! 这就是在 SQL Server Management Studio 2017 中对我有用的方法:SELECT * FROM [dbo]. WHERE @@ROWCOUNT BETWEEN 跨度> 太棒了,它在 MS SQL Server 2017 select Statement 中就像魅力一样工作 这对于任何当前的 SQL Server 版本都不是一个好的答案。这将扫描整个表以在过滤之前计算ROW_NUMBER()【参考方案4】:

如果我没记错的话(我已经有一段时间没有使用 SQL Server 了)你可以使用这样的东西:(2005 年及以上)

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

【讨论】:

SQL Server 2012: Msg 207, Level 16, State 1, Line 5 列名“RowNum”无效。 听起来你的陈述中有错字。 RowNum 是我们分配给表达式的名称。将您的问题发布到来源,社区将为您提供帮助 这是无效的语法。您不能在 WHERE 中引用在同一级别 SELECT 子句中定义的别名。【参考方案5】:

这几乎是我在 10 月份提出的一个问题的重复: Emulate MySQL LIMIT clause in Microsoft SQL Server 2000

如果您使用的是 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;

您也可以将其写为common table expression,如@Leon Tayson 的answer 所示。

【讨论】:

ROW_NUMBER() OVER (ORDER BY) 在 ANSI SQL:2003 中获得积分,尽管在 SQL Server 以外的 DBMS 中的支持非常参差不齐。当然,它非常笨重...... @bobince:原来 Oracle、Microsoft SQL Server 2005、IBM DB2 和 PostgreSQL 8.4 都支持窗口函数。这涵盖了 SQL 市场的绝大部分。仅当您使用 MySQL、SQLite 或上述数据库的旧版本时,支持才会参差不齐。【参考方案6】:
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() 条件下停止。【参考方案7】:

这是一个多步骤的方法,适用于 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

【讨论】:

【参考方案8】:

从语法上讲,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 

【讨论】:

【参考方案9】:
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;

【讨论】:

对我来说是一个很好的解决方案。【参考方案10】:

这是我尽量避免使用 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 行之间的数据(而不是搜索整个数据集并限制输出)。

【讨论】:

【参考方案11】:

从 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/en-us/library/ms188385(v=sql.110).aspx

当 order by 不唯一时,这可能无法正常工作。

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

【讨论】:

使用 'with' 只需要一半的时间即可完成查询 - 请参阅@Leon Tayson 的答案。我不知道微软做了什么让它这么慢。 为什么这不是公认的答案?我们在 2018 大声呼喊! @Skipper 对。接受的仍然有效。让我们对此进行投票以反映更新。 @kronn 作品与“好”不同。该查询将扫描并锁定整个表【参考方案12】:

这就是我在 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 是您要从表中开始拉取的记录/行号,即:如果表 1 中有 40 条记录,则上面的代码将从第 10 行开始拉取。

yy 是您要从表中提取的记录/行数。

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

查看链接了解更多关于OFFSET的信息

【讨论】:

同意这一点。对我来说,我需要将此条件用于我的自定义本机查询,因此 JPA 的 vanilla findBy 子句没有多大帮助。此选项按预期工作。请将此页面视为我见过的最佳参考:sqlservertutorial.net/sql-server-basics/sql-server-offset-fetch【参考方案13】:

在 SQL 中不存在 LIMIT 关键字。如果您只需要有限数量的行,您应该使用类似于 LIMIT 的 TOP 关键字。

【讨论】:

【参考方案14】:

必须尝试。在下面的查询中,您可以看到分组依据、排序依据、跳过行和限制行。

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

【讨论】:

【参考方案15】:

如果您的 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 中选择 *

【讨论】:

【参考方案16】:

在 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] 并为每一行分配一个唯一的计数而不订购一些东西,然后再次重新选择您可以提供限制的地方.. :)

【讨论】:

【参考方案17】:

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

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

【讨论】:

【参考方案18】:

简单的方法

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 是必填项

【讨论】:

以上是关于如何使用 SQL Server 实现 LIMIT? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQL Server 2005 中使用 LIMIT [X] OFFSET [Y] [重复]

Sql Server实现limit用法

Sql Server实现limit用法

MySQL用limit代替SQL Server :top

等效于 SQL SERVER 的 MySQL LIMIT 子句

MS SQL Server 2005 中的 LIMIT 样式功能