2009-10-06 74 views
13

我在推廣一個Django DB複製應用程序的過程中,它使用的語句:SQL中的LIMIT語句的通用性如何?

SELECT %s FROM %s LIMIT 1 

獲取1行,使用Python DBAPI來形容領域,它正常工作與Oracle和MySQL,但,LIMIT聲明如何跨平臺?

+0

什麼版本的Oracle做這項工作? – 2009-10-07 01:17:42

+0

ORACLE 9i @ AlphaServer,我的錯誤,只是試了一下,不起作用:( – 2009-10-07 02:46:53

回答

2

它不適用於MSSQL(使用SELECT TOP 10 * FROM Blah代替)。這削減了大部分數據庫市場。我不確定其他人。

另外,雖然不太可能,但您的數據庫API可能會爲您翻譯它。

2

限制是不是ANSI SQL標準爲1992年標準的一部分;我沒有任何後來的標準副本。在最好的時候,供應商對標準的遵守情況非常模糊。對於它的價值,「LIMIT」被列爲保留字(意思是即使在實現中不是關鍵字的情況下它也不能合法地用作標識符)。

12

LIMIT離通用RDBMS非常遙遠,它幾乎侷限於MySQL和PostgreSQL。 Here是如何在許多其他實現中完成的詳細分析,包括MSSQL,Oracle和DB2以及ANSI SQL。

6

這並不普遍。其實我很驚訝它在Oracle爲你工作;它以前不曾存在。通常Oracle用戶使用ROWNUM

每個數據庫都有自己的語法,用於按行號限制結果。還有兩種方法是ANSI標準SQL:

  1. FETCH FIRST。源自DB/2並且僅在SQL:2008中制定標準,所以對DBMS的支持非常少。不能使用偏移量。開窗功能SELECT ..., ROW_NUMBER() OVER (ORDER BY some_ordering) AS rn WHERE rn BETWEEN n AND m ... ORDER BY some_ordering。這是來自SQL:2003,並且在較新的DBMS中有一些(不規則的,有時很慢)的支持。它可以在行號上使用偏移量或任何其他比較函數,但有一個醜陋的缺點。

Here's a good overview如果您希望跨DBMS分頁支持,您將不得不處理的繁瑣工作。

+0

+1對於跨平臺表達LIMIT的一個非常好的鏈接 – ash108 2013-02-18 18:08:27

20

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

選擇你的毒藥;-)

+0

在SQL Server中,使用OFFSET和FETCH NEXT需要使用一個ORDER BY子句 – BoltBait 2014-09-24 00:45:10

+0

@BoltBait:你說得對,我一直忘記這個,謝謝! – 2014-09-24 13:58:31

+0

所以這些語句都會跳過兩個元素並返回一個,對吧?用「無偏移量」這個語句的例外。 – 2017-03-16 15:35:16