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

我对 MySQL 进行了以下查询:

select * from table1 LIMIT 10,20

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

【问题讨论】:

标签: sql sql-server migration


【解决方案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的信息

        【讨论】:

        【解决方案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 是必填项

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2012-05-07
                    • 2011-09-29
                    • 1970-01-01
                    • 2010-10-02
                    • 2013-04-20
                    • 2012-05-13
                    相关资源
                    最近更新 更多