代码之家  ›  专栏  ›  技术社区  ›  Bill Karwin

在Microsoft SQL Server 2000中模拟MySQL限制子句

  •  38
  • Bill Karwin  · 技术社区  · 17 年前

    当我在工作的时候 Zend Framework's database component ,我们试图抽象 LIMIT 由MySQL、PostgreSQL和SQLite支持的子句。也就是说,可以通过以下方式创建查询:

    $select = $db->select();
    $select->from('mytable');
    $select->order('somecolumn');
    $select->limit(10, 20);
    

    当数据库支持 限度 ,这将生成如下所示的SQL查询:

    SELECT * FROM mytable ORDER BY somecolumn LIMIT 10, 20
    

    对于不支持该功能的品牌数据库来说,这更为复杂 限度 (顺便说一句,该条款不是标准SQL语言的一部分)。如果可以生成行号,则将整个查询作为派生表,并在外部查询中使用 BETWEEN .这是针对Oracle和IBM DB2的解决方案。Microsoft SQL Server 2005具有类似的行号函数,因此可以通过以下方式编写查询:

    SELECT z2.*
    FROM (
        SELECT ROW_NUMBER OVER(ORDER BY id) AS zend_db_rownum, z1.*
        FROM ( ...original SQL query... ) z1
    ) z2
    WHERE z2.zend_db_rownum BETWEEN @offset+1 AND @offset+@count;
    

    但是,Microsoft SQL Server 2000没有 ROW_NUMBER() 作用

    所以我的问题是,你能想出一个方法来模仿 限度 在Microsoft SQL Server 2000中仅使用SQL的功能?不使用游标、T-SQL或存储过程。它必须支持这两种观点 限度 ,计数和偏移。使用临时表格的解决方案也是不可接受的。

    编辑:

    MS SQL Server 2000最常见的解决方案似乎如下所示,例如获取第50行到第75行:

    SELECT TOP 25 *
    FROM ( 
      SELECT TOP 75 *
      FROM   table 
      ORDER BY BY field ASC
    ) a 
    ORDER BY field DESC;
    

    然而,如果总的结果集是,比如说60行,这就不起作用。内部查询返回60行,因为这是前75行。然后外部查询返回第35-60行,这与所需的50-75“页面”不符。基本上,这个解决方案是有效的,除非你需要的结果集的最后一个“页面”不是页面大小的倍数。

    编辑:

    另一种解决方案效果更好,但前提是您可以假设结果集包含唯一的列:

    SELECT TOP n *
    FROM tablename
    WHERE key NOT IN (
        SELECT TOP x key
        FROM tablename
        ORDER BY key
    );
    

    结论:

    似乎没有通用的解决方案可供效仿 限度 在MS SQL Server 2000中。如果您可以使用 行号() MS SQL Server 2005中的函数。

    4 回复  |  直到 17 年前
        1
  •  5
  •   Florian Fankhauser    16 年前

    这里是另一个只在SQLServer2005和更新版本中工作的解决方案,因为它使用except语句。但我还是分享了。 如果你想得到50-75的记录,写:

    select * from (
        SELECT top 75 COL1, COL2
        FROM MYTABLE order by COL3
    ) as foo
    except
    select * from (
        SELECT top 50 COL1, COL2
        FROM MYTABLE order by COL3
    ) as bar
    
        2
  •  5
  •   TazGPL    13 年前
    SELECT TOP n *
    FROM tablename
    WHERE key NOT IN (
        SELECT TOP x key
        FROM tablename
        ORDER BY key
        DESC
    );
    
        3
  •  4
  •   grr grr    17 年前

    当您只需要限制时,ms sql具有等效的TOP关键字,这一点很清楚。 当你需要对偏移量进行限制时,你可以尝试前面描述的一些方法,但它们都会增加一些开销,例如,订购一种方式,然后订购另一种方式,或者expencive不运行。 我认为不需要所有这些级联。在我的建议中,最干净的解决方案就是在SQL端使用TOP而不是offset,然后使用适当的客户机方法(比如php中的mssql_data_seek)查找所需的起始记录。虽然这不是一个纯粹的SQL解决方案,但我认为它是最好的解决方案,因为它不会增加任何开销(跳过的记录不会在网络上传输,如果这是您担心的话)。

        4
  •  0
  •   Barka Abe Miessler    14 年前

    我会尝试在我的ORM中实现这一点,因为它非常简单。如果它真的需要在SQL Server中,那么我将查看linq to SQL为下面的linq to SQL语句生成的代码,并从那里开始。实现该代码的MSFT工程师多年来一直是SQL团队的一员,他知道自己在做什么。

    var result=myDataContext。我的桌子。跳过(页面索引*页面大小)。Take(页面大小)