如何使用 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].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] [重复]