在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中的LIMIT
function,只使用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)