我知道:
- 火鸟:
FIRST
和SKIP
; - mysql:
LIMIT
; - SQL 服务器:
ROW_NUMBER()
;
有人知道执行结果分页的 SQL ANSI 方式吗?
请参阅此页面上的限制 - 带偏移部分:http://troels.arvin.dk/db/rdbms/
顺便说一句,Firebird 从 2.0 版开始也支持 ROWS 子句
现在有一个标准,不一定是 ANSI 标准(人们给出了很多答案,我认为这是不那么冗长的一个)
SELECT * FROM t1
WHERE ID > :lastId
ORDER BY ID
FETCH FIRST 3 ROWS ONLY
但并非所有数据库都支持它,下面列出了所有支持的数据库
您当然可以使用偏移样式,尽管您可能会遇到性能问题
SELECT * FROM t1
ORDER BY ID
OFFSET 0 ROWS
FETCH FIRST 3 ROWS ONLY
它有不同的支持
没有官方方式,没有。*
通常,您会希望在数据库访问层中有一个抽象函数来处理它;提示您使用的是 MySQL 或 PostgreSQL,它可以在查询中添加“LIMIT”子句,或者在 Oracle 的子查询上添加 rownum 等等。如果它不知道它可以做任何这些,则退回到获取批次并仅返回完整列表的一部分。
*: eta: 现在有,在 ANSI SQL:2003 中。但它不是全球支持的,它经常表现不佳,而且有点痛苦,因为您必须将您的 ORDER 移动/复制到语句中的新位置,这使得自动换行变得更加困难:
SELECT * FROM (
SELECT thiscol, thatcol, ROW_NUMBER() OVER (ORDER BY mtime DESC, id) AS rownumber
)
WHERE rownumber BETWEEN 10 AND 20 -- care, 1-based index
ORDER BY rownumber;
SQL:2008(以及它的起源地 DB2)中还有“FETCH FIRST n ROWS ONLY”后缀。但是就像 SQL Server 中的 TOP 前缀和 Informix 中类似的语法一样,您无法指定起点,因此您仍然必须获取并丢弃一些行。
将您的结果插入存储表中,按照您希望的显示方式进行排序,但使用新的 IDENTITY 列。
现在从该表中选择您感兴趣的 ID 范围。
(完成后一定要清理桌子)
或者在客户端上做,因为与演示有关的任何事情通常都不应该在 SQL Server 上做(在我看来)
ANSI Sql example:
offset=41, fetchsize=10
SELECT TOP(10) *
FROM table1
WHERE table1.ID NOT IN (SELECT TOP(40) table1.ID FROM table1)
对于分页,我们需要一个RowNo
列来过滤它 - 它应该在一个字段上id
- 有两个变量,如@PageNo
和@PageRows
。所以我使用这个查询:
SELECT *
FROM (
SELECT *, (SELECT COUNT(1)
FROM aTable ti
WHERE ti.id < t.id) As RowNo
FROM aTable t) tr
WHERE
tr.RowNo >= (@PageNo - 1) * @PageRows + 1
AND
tr.RowNo <= @PageNo * @PageRows
我知道我对这个问题非常非常晚,但它仍然是这个问题的最佳结果之一。
然而,这个问题缺少的一个回答是,我相信“正确”的 ANSI SQL 分页方法,至少如果你想要最大的可移植性,是根本不使用LIMIT
/ OFFSET
/FIRST
等,而是做类似的事情:
SELECT *
FROM MyTable
WHERE ColumnA > ?
ORDER BY ColumnA ASC
where?
是使用支持它们的库的参数(例如PDO
在 PHP 中)。
这里的想法很简单,当获取第一页时,我们传递一个匹配每个可能行的参数,例如,如果ColumnA
是文本,我们将传递一个空字符串 ( ''
)。然后我们读入尽可能多的结果,然后发布其余的。这可能意味着在后台获取了一些额外的行,但我们这里的优先级是兼容性。
为了获取下一页,我们ColumnA
从结果中的最后一行获取 的值,并将其作为参数传入,这样我们只会获取出现在它之后的值。要在另一个方向运行相同的查询,只需交换>
for<
和ASC
for DESC
。
这种方法有一些重要的注意事项:
mango
,但是自从获取它之后,为apple
and添加了行carrot
,那么mango
现在也可能出现在下一页上,因为它已按排序顺序移动。通过使用这种情况是ColumnA > 'mango'
不可能发生的。DATETIME
这在您按 a 进行排序且频繁更新的情况下非常有用。>
到<
和ASC
到)时颠倒提到的排序顺序并从每页结果的第一行而不是最后一行DESC
传递值。ColumnA
请注意,如果将值添加到您的表中,则可能意味着您的第一页可能会更短,但这是一个相当小的问题。N + 1
行,其中N
是您想要每页的行数,这样您可以检测是否还有更多行要获取。ORDER BY
子句(和WHERE
条件)以包含足够多的列以使每一行都是唯一的。所以它不是没有一些问题,但它是迄今为止最兼容的方法,因为每个 SQL 数据库都会支持它。
顺便说一句,Troels,PostgreSQL 支持限制/偏移