在Microsoft SQL Server 2000中模拟MySQL LIMIT子句

当我处理Zend Framework的数据库组件时 ,我们试图抽象MySQL,PostgreSQL和SQLite支持的LIMIT子句的function。 也就是说,创build一个查询可以这样做:

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

当数据库支持LIMIT ,会产生如下的SQL查询:

 SELECT * FROM mytable ORDER BY somecolumn LIMIT 10, 20 

这对于不支持LIMIT的数据库品牌来说更为复杂(顺便提一下,该子句不是标准SQL语言的一部分)。 如果可以生成行号,则使整个查询成为派生表,并在外部查询中使用BETWEEN 。 这是Oracle和IBM DB2的解决scheme。 Microsoft SQL Server 2005有一个相似的行号function,所以可以这样写查询:

 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中的LIMITfunction,只使用SQL? 不使用游标或T-SQL或存储过程。 它必须支持LIMIT两个参数,包括count和offset。 使用临时表的解决scheme也是不可接受的。

编辑:

MS SQL Server 2000最常见的解决scheme似乎如下所示,例如获取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所需的“页面”。 基本上,这个解决scheme的工作原理除非你需要一个结果集的最后一个“页面”,这个页面并不是页面大小的倍数。

编辑:

另一个解决scheme效果更好,但只有当您可以假设结果集包含一个唯一的列时:

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

结论:

似乎没有通用的解决scheme来模拟MS SQL Server 2000中的LIMIT 。如果您可以使用MS SQL Server 2005中的ROW_NUMBER()函数,则存在一个好的解决scheme。

这是另一个解决scheme,只能在Sql Server 2005和更新版本中使用,因为它使用了except语句。 但是我分享它。 如果你想获得logging50 – 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 

当你只需要LIMIT时,ms sql有相应的TOP关键字,这样就清楚了。 当你需要使用OFFSET的LIMIT,你可以尝试一些像前面描述的黑客攻击,但是它们都会增加一些开销,也就是用于一种方法,然后是另一种方式,或者是一种非运营的方式。 我认为所有这些级联都是不需要的。 在我的oppinion最干净的解决scheme将只是使用顶部没有抵消的SQL方面,然后寻求所需的起始logging与适当的客户端方法,如在PHP中的mssql_data_seek。 虽然这不是纯粹的SQL解决scheme,但我认为这是最好的解决scheme,因为它不会增加任何开销(跳过的logging不会在networking上传输,如果这是您所担心的)。

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

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

var result = myDataContext.mytable.Skip(pageIndex * pageSize).Take(pageSize)