2009-10-06 10 views
13

estoy en el proceso de generalización de una aplicación de la replicación Django DB y se utiliza la sentencia:¿Qué tan universal es la instrucción LIMIT en SQL?

SELECT %s FROM %s LIMIT 1 

en busca de 1 fila y utilizar el DBAPI Python para describir los campos, que funciona bien con Oracle y MySQL, pero , ¿qué plataforma cruzada es la instrucción LIMIT?

+0

¿Qué versión de Oracle hace que el trabajo en? –

+0

ORACLE 9i @ AlphaServer, mi error, simplemente lo intenté, no funciona :( –

Respuesta

2

No funciona en MSSQL (que usa SELECT TOP 10 * FROM Blah en su lugar). Eso corta una porción significativa del mercado de DB. No estoy seguro acerca de los demás.

Además, es posible, aunque muy poco probable, que su DB API lo traduzca por usted.

2

límite no es parte del estándar ANSI SQL como de la norma de 1992; No tengo una copia de ningún estándar posterior a mano. El cumplimiento de los proveedores con el estándar es bastante vago en el mejor de los casos. Por lo que vale, "LIMIT" aparece como una palabra reservada (lo que significa que legalmente no se puede usar como identificador incluso en los casos en que no es una palabra clave en la implementación).

12

LIMIT está muy lejos de ser universal: de los principales RDBMS, está prácticamente restringido a MySQL y PostgreSQL. Here es un análisis detallado de cómo se hace esto en muchas otras implementaciones, incluidas MSSQL, Oracle y DB2, así como en ANSI SQL.

6

No es para nada universal. En realidad, estoy sorprendido de que funcione para usted en Oracle; no solía estar presente. Normalmente, los usuarios de Oracle van por ROWNUM.

Cada base de datos tiene su propia sintaxis para limitar los resultados por número de fila. También hay dos métodos que son estándar ANSI SQL:

  1. FETCH FIRST. Derivado de DB/2 y solo hecho estándar en SQL: 2008, por lo que es muy poco compatible con DBMS. No se puede usar un desplazamiento.

  2. La función ventana SELECT ..., ROW_NUMBER() OVER (ORDER BY some_ordering) AS rn WHERE rn BETWEEN n AND m ... ORDER BY some_ordering. Esto es de SQL: 2003 y tiene cierto soporte (desigual, a veces lento) en los DBMS más nuevos. Puede usar un desplazamiento o cualquier otra función de comparación en el número de fila, pero tiene el inconveniente de ser terriblemente feo.

Here's a good overview de lo tedioso que tendrá que hacer frente si quiere el apoyo de paginación cruzada DBMS.

+0

+1 para un enlace realmente bueno en formas multiplataforma para expresar LIMIT. – ash108

20

LIMIT ha vuelto muy popular con una variedad de bases de datos de código abierto, pero, por desgracia, el hecho es que la paginación OFFSET ha sido acerca de la función de SQL estandarizado menos de todos ellos, después de haber sido estandarizado tan tarde como en SQL:2008.

Hasta entonces, el jOOQ user manual page on the LIMIT clause muestra cómo las diversas declaraciones equivalentes se pueden formar en cada dialecto 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 

Ahora, estos eran todos bastante sencillo, ¿verdad? Aquí viene la parte desagradable, cuando se tiene que emular a ellos:

-- 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

Elige tu veneno ;-)

+0

En SQL Server, usar OFFSET y FETCH NEXT requiere el uso de una cláusula ORDER BY – BoltBait

+0

@BoltBait: tienes razón, sigo olvidándome de esto. ¡Gracias! –

+0

Así que estas declaraciones saltan dos elementos y devuelven uno, ¿verdad? Con la obvia excepción de las declaraciones tituladas "sin compensación". –