代码之家  ›  专栏  ›  技术社区  ›  Roberto Rosario

限制语句在SQL中的通用性如何?

  •  15
  • Roberto Rosario  · 技术社区  · 15 年前

    我正在推广Django DB复制应用程序,它使用以下语句:

    SELECT %s FROM %s LIMIT 1
    

    要获取1行并使用python dbapi来描述这些字段,它可以很好地与Oracle和MySQL配合使用,但是,limit语句的跨平台性如何?

    7 回复  |  直到 6 年前
        1
  •  10
  •   Roubo BoltBait    6 年前

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

    我认为最好的方法是在select语句之前使用set rowcount命令。

    所以,对你来说:

    SET ROWCOUNT 1
    SELECT %s FROM %s
    
        2
  •  23
  •   Lukas Eder    7 年前

    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

    选择你的毒药;-)

        3
  •  12
  •   Pavel Minaev    15 年前

    LIMIT 它离通用性还很远——在主要的RDBMS中,它几乎只限于MySQL和PostgreSQL。 Here 详细分析了如何在许多其他实现(包括MSSQL、Oracle和DB2)以及ANSI SQL中实现这一点。

        4
  •  7
  •   bobince    15 年前

    这根本不是万能的。实际上,我很惊讶它在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中有一些(补丁,有时速度较慢)支持。它可以在行号上使用偏移量或任何其他比较函数,但缺点是非常难看。

    Here's a good overview 如果您想要跨DBMS分页支持,那么就必须处理繁琐的工作。

        5
  •  2
  •   rmeador    15 年前

    它不适用于MSSQL(使用 SELECT TOP 10 * FROM Blah 取而代之的是)这切断了数据库市场的很大一部分。我不确定其他人。

    此外,您的DBAPI可能(尽管可能性很小)会为您翻译它。

        6
  •  2
  •   Tim Martin    15 年前

    从1992年起,限制并不是ANSI SQL标准的一部分;我没有任何后期标准的副本。在最好的情况下,供应商对标准的遵守是相当模糊的。就其价值而言,“限制”被列为一个保留字(意味着它在法律上不能用作标识符,即使在实现中它不是关键字的情况下)。

        7
  •  1
  •   Susa    6 年前

    由于其中一个答案提到了极限和偏移量或多或少局限于MySQL和PostgreSQL,我想指出SAP HANA也支持极限和偏移量子句。但SAP HANA数据库中不允许无限制的偏移。