SQL中的LIMIT语句有多普遍?

时间:2009-10-06 23:15:45

标签: sql database rdbms

我正在推广Django数据库复制应用程序,它使用语句:

SELECT %s FROM %s LIMIT 1

获取1行并使用Python DBAPI来描述字段,它可以正常使用ORACLE和MySQL,但是,跨平台是如何使用LIMIT语句的?

7 个答案:

答案 0 :(得分:23)

LIMIT已经变得非常受各种开源数据库的欢迎,但不幸的是,事实是OFFSET分页一直是关于它们的最不标准化的SQL特性,已被标准化为已故如在SQL:2008中那样。

在此之前,jOOQ user manual page on the LIMIT clause显示了如何在每种SQL方言中形成各种等效语句:

-- MySQL, H2, HSQLDB, Postgres, and SQLite
SELECT * FROM BOOK LIMIT 1 OFFSET 2

-- CUBRID supports a MySQL variant of the LIMIT .. OFFSET clause
SELECT * FROM BOOK LIMIT 2, 1

-- Derby, SQL Server 2012, Oracle 12c, SQL:2008 standard
-- Some need a mandatory ORDER BY clause prior to OFFSET
SELECT * FROM BOOK [ ORDER BY ... ] OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY

-- Ingres
SELECT * FROM BOOK OFFSET 2 FETCH FIRST 1 ROWS ONLY

-- Firebird
SELECT * FROM BOOK ROWS 2 TO 3

-- Sybase SQL Anywhere
SELECT TOP 1 ROWS START AT 3 * FROM BOOK

-- DB2 (without OFFSET)
SELECT * FROM BOOK FETCH FIRST 1 ROWS ONLY

-- Sybase ASE, SQL Server 2008 (without OFFSET)
SELECT TOP 1 * FROM BOOK

现在,这些都很直接,对吧?当你必须模仿它们时,这就是令人讨厌的部分:

-- DB2 (with OFFSET), SQL Server 2008 (with OFFSET), 
SELECT * FROM (
  SELECT BOOK.*, 
    ROW_NUMBER() OVER (ORDER BY ID ASC) AS RN
  FROM BOOK
) AS X
WHERE RN > 2
AND RN <= 3

-- DB2 (with OFFSET), SQL Server 2008 (with OFFSET)
-- When the original query uses DISTINCT!
SELECT * FROM (
  SELECT DISTINCT BOOK.ID, BOOK.TITLE 
    DENSE_RANK() OVER (ORDER BY ID ASC, TITLE ASC) AS RN
  FROM BOOK
) AS X
WHERE RN > 2
AND RN <= 3

-- Oracle 11g and less
SELECT * 
FROM (
  SELECT b.*, ROWNUM RN 
  FROM (
    SELECT *
    FROM BOOK
    ORDER BY ID ASC
  ) b
  WHERE ROWNUM <= 3
) 
WHERE RN > 2

Read about the ROW_NUMBER() vs. DENSE_RANK() rationale here

选择你的毒药; - )

答案 1 :(得分:12)

LIMIT远非普遍 - 在主要的RDBMS之外,它几乎仅限于MySQL和PostgreSQL。 Here详细分析了如何在许多其他实现中完成此操作,包括MSSQL,Oracle和DB2,以及ANSI SQL。

答案 2 :(得分:10)

http://en.wikipedia.org/wiki/Select_(SQL)#Limiting_result_rows列出了select命令的所有主要变体。

我认为最好的方法是在SELECT语句之前使用SET ROWCOUNT命令。

所以,对你来说:

SET ROWCOUNT 1
SELECT %s FROM %s

答案 3 :(得分:7)

它根本不普遍。实际上我很惊讶它在Oracle中为你工作;它曾经不存在。通常,Oracle用户会选择ROWNUM

每个数据库都有自己的语法,用于按行号限制结果。还有两种方法是ANSI标准SQL:

  1. FETCH FIRST。源自DB / 2并且仅在SQL:2008中成为标准,因此对DBMS的支持非常少。不能使用抵消。

  2. 窗口函数SELECT ..., ROW_NUMBER() OVER (ORDER BY some_ordering) AS rn WHERE rn BETWEEN n AND m ... ORDER BY some_ordering。这是来自SQL:2003并且在较新的DBMS中具有一些(补丁,有时慢)支持。它可以在行号上使用偏移量或任何其他比较函数,但有一个令人难以置信的难看的缺点。

  3. 如果您想要跨DBMS分页支持,那么您将不得不处理这些乏味的问题。

答案 4 :(得分:2)

它不适用于MSSQL(使用SELECT TOP 10 * FROM Blah代替)。这削减了数据库市场的重要部分。我不确定别人。

此外,您的数据库API可能会为您翻译它,但这种可能性很小。

答案 5 :(得分:2)

LIMIT不是1992年标准中ANSI SQL标准的一部分;我手边没有任何后来标准的副本。在最好的时候,供应商对标准的遵守是非常模糊的。对于它的价值,“LIMIT”被列为保留字(意味着即使在实现中它不是关键字的情况下,它也不能合法地用作标识符)。

答案 6 :(得分:1)

由于在其中一个答案中提到LIMIT和OFFSET或多或少局限于MySQL和PostgreSQL,我想指出SAP HANA也支持LIMIT和OFFSET子句。但SAP HANA数据库中不允许使用不带LIMIT的OFFSET。