php – Zend DB无法模拟MS SQL的限制和偏移量

我正在使用Zend Framework 1.12来访问MSsql 2008服务器.我使用FreeTDS作为数据库驱动程序.

我正在使用Zend_Db生成以下查询.

$obj_sel = $obj_db
          -> select ()
          -> from (array ('ps' => 'ProductStock'),array ('PLU','stock' => 'SUM(ps.stock)'))
          -> join (array ('pc' => 'ProductCatalogue'),'ps.PLU = pc.PLU',NULL)
          -> join (array ('gl' => 'gemini_Location'),'ps.Location = gl.LocationID',array ('LocationID'))
          -> where ('ps.status = 1')
          -> where ('ps.PLU IS NOT NULL');
           > where ('pc.rootPLU >= ?',$this -> int_start_rootplu);
          -> group ('ps.PLU')
          -> group ('gl.LocationID')
          -> order (array ('ps.PLU','gl.LocationID'));

如果我运行并执行此操作,我会得到一个看起来很好并且正确的查询.

SELECT "ps"."PLU",SUM(ps.stock) AS "stock","gl"."LocationID" FROM "ProductStock" AS "ps"
 INNER JOIN "ProductCatalogue" AS "pc" ON ps.PLU = pc.PLU
 INNER JOIN "gemini_Location" AS "gl" ON ps.Location = gl.LocationID WHERE (ps.status = 1) AND (ps.PLU IS NOT NULL) AND (pc.rootPLU >= 93838) GROUP BY "ps"."PLU","gl"."LocationID" ORDER BY "ps"."PLU" ASC,"gl"."LocationID" ASC

但是当我尝试向查询添加限制或偏移时,如下所示:

$obj_sel = $obj_db
          -> select ()
          -> from (array ('ps' => 'ProductStock'),'gl.LocationID'))
          -> limit (1000,2000);

我得到以下查询sql服务器拒绝执行.

SELECT * FROM (SELECT TOP 1000 * FROM (SELECT TOP 3000 "ps"."PLU","gl"."LocationID" ASC) AS inner_tbl ORDER BY "ps"."PLU","gl"."LocationID" DESC) AS outer_tbl ORDER BY "ps"."PLU","gl"."LocationID" asc

我收到以下错误

sqlSTATE[HY000]: General error: 4104 General sql Server error: Check messages from the sql Server [4104] (severity 16) [(null)]

我不像MSsql那样熟悉MysqL或Postgres,所以我不得不假设TOP技术是正确的.但是,很明显,无论sql Zend DB在这里生成什么都是不对的.

这是Zend DB中的已知问题吗?如果是这样,我该如何解决呢?

解决方法

ZF 1没有正确地在sql Server上实现分页,尽管ZF 2确实如此.

我通过继承Zend_Db_Adapter_Pdo_Mssql解决了这个问题:

class My_Zend_Db_Adapter_Pdo_Mssql extends Zend_Db_Adapter_Pdo_Mssql
{
    /**
     * @see Zend_Db_Adapter_Pdo_Mssql::limit()
     */
    public function limit($sql,$count,$offset = 0)
    {
        $count = intval($count);
        if ($count <= 0) {
            /** @see Zend_Db_Adapter_Exception */
            require_once 'Zend/Db/Adapter/Exception.PHP';
            throw new Zend_Db_Adapter_Exception('count parameter invalid: ' . $count);
        }

        $offset = intval($offset);
        if ($offset < 0) {
            /** @see Zend_Db_Adapter_Exception */
            require_once 'Zend/Db/Adapter/Exception.PHP';
            throw new Zend_Db_Adapter_Exception('offset parameter invalid: ' . $count);
        }

        if (0 == $offset) {
            $sql = preg_replace('/^SELECT\s+(disTINCT\s)?/i','SELECT $1TOP ' . ($count+$offset) . ' ',$sql);
            return $sql;
        }

        $selectStart = stripos($sql,'SELECT');
        $fromStart = stripos($sql,'FROM');

        $orderby = stristr($sql,'ORDER BY');

        if ($orderby === false) {
            $orderby = 'ORDER BY (SELECT 1)';
        }

        $sql = rtrim(str_replace($orderby,'',$sql));

        $selectParams = trim(substr($sql,$selectStart + 6,$fromStart - $selectStart - 6));
        $selectParams .= ',ROW_NUMBER() OVER (' . $orderby . ') AS [ZEND_ROW_NUMBER]';

        $sql = substr($sql,$selectStart + 6) . ' ' . $selectParams . ' ' . substr($sql,$fromStart);

        $outersql = 'SELECT * FROM (' . $sql . ') AS [ZEND_OFFSET_EMULATION]'
                  . ' WHERE [ZEND_OFFSET_EMULATION].[ZEND_ROW_NUMBER] BETWEEN '
                  . ($offset + 1) . ' AND '
                  . ($offset + $count)
                  . ' ORDER BY [ZEND_ROW_NUMBER] ASC';

        return $outersql;
    }
}

相关文章

统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
前言 之前做了微信登录,所以总结一下微信授权登录并获取用户...
FastAdmin是我第一个接触的后台管理系统框架。FastAdmin是一...
之前公司需要一个内部的通讯软件,就叫我做一个。通讯软件嘛...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...