ZF2 Union + Pagination

与世无争的帅哥 提交于 2019-12-25 02:10:33

问题


I'm using ZF2 and SQL Server 2012. I'm trying to write a union query with pagination.

It seems like support for unions in ZF2 is not fully there. There is no union() method, but I see that there is a combine() method. It creates the query with the union, but it puts the ORDER BY on the first query instead of on the entire unioned query. So when the ZF2 paginator tries to add the limit/offset parts, SQL Server chokes because it has to have an ORDER BY on the whole query.

Here is my code:

public function fetchPage($fkADUser, array $orderBy, $page = 1, $limit = 20) {

    $inboxSelect = $this->inboxTableGateway->getSql()
        ->select()
        ->columns([
            'pkid',
        ])
        ->join(['f' => 'Fax'], 'FaxInbound.fkFax = f.pkid', [
            'PageCount',
            'CreateTime',
        ])
        ->where(['f.fkADUser = ?' => $fkADUser])
        ->where('FaxInbound.DeleteTime IS NOT NULL');

    $sentSelect = $this->sentTableGateway->getSql()
        ->select()
        ->columns([
            'pkid',
        ])
        ->join(['f' => 'Fax'], 'FaxOutbound.fkFax = f.pkid', [
            'PageCount',
            'CreateTime',
        ])
        ->where(['f.fkADUser = ?' => $fkADUser])
        ->where('FaxOutbound.DeleteTime IS NOT NULL');

    $inboxSelect->combine($sentSelect)->order($orderBy);

    return $this->inboxTableGateway->paginate($inboxSelect, $page, $limit, $this->resultSetPrototype);
}

And here is the query generated (from SQL Profiler):

(
    SELECT
        [FaxInbound].[pkid] AS [pkid],
        [f].[PageCount] AS [PageCount],
        [f].[CreateTime] AS [CreateTime]
    FROM
        [FaxInbound]
        INNER JOIN [Fax] AS [f]
            ON [FaxInbound].[fkFax] = [f].[pkid]
    WHERE
        f.fkADUser = @P1
        AND FaxInbound.DeleteTime IS NOT NULL
    ORDER BY
        [CreateTime] DESC
) UNION (
    SELECT
        [FaxOutbound].[pkid] AS [pkid],
        [f].[PageCount] AS [PageCount],
        [f].[CreateTime] AS [CreateTime]
    FROM
        [FaxOutbound]
        INNER JOIN [Fax] AS [f]
            ON [FaxOutbound].[fkFax] = [f].[pkid]
    WHERE
        f.fkADUser = @P2
        AND FaxOutbound.DeleteTime IS NOT NULL
)
OFFSET 0 ROWS
FETCH NEXT 20 ROWS ONLY

Notice that the ORDER BY is on the first query instead of the entire unioned query. So the error messages I get are:

Msg 156, Level 15, State 1, Line 13
Incorrect syntax near the keyword 'ORDER'.
Msg 102, Level 15, State 1, Line 28
Incorrect syntax near 'OFFSET'.
Msg 153, Level 15, State 2, Line 29
Invalid usage of the option NEXT in the FETCH statement.

But if I move the ORDER BY outside, just before the OFFSET, the query works.

So the question is, does anyone know how to put the ORDER BY on the whole query instead of the first one? Or, Is there a way for me to use the ZF2 Paginator with a manually written query?


回答1:


Looks like there is a bug in ZF2. I added it to the ZF2 issue tracker.

I fixed the issue by reordering the entries in Zend\Db\Sql\Select::$specifications.

Original:

protected $specifications = array(
    'statementStart' => '%1$s',
    self::SELECT => array(...),
    self::JOINS  => array(...),
    self::WHERE  => 'WHERE %1$s',
    self::GROUP  => array(...),
    self::HAVING => 'HAVING %1$s',
    self::ORDER  => array(...),
    self::LIMIT  => 'LIMIT %1$s',
    self::OFFSET => 'OFFSET %1$s',
    'statementEnd' => '%1$s',
    self::COMBINE => '%1$s ( %2$s )',
);

New:

protected $specifications = array(
    'statementStart' => '%1$s',
    self::SELECT => array(...),
    self::JOINS  => array(...),
    self::WHERE  => 'WHERE %1$s',
    self::GROUP  => array(...),
    self::HAVING => 'HAVING %1$s',
    'statementEnd' => '%1$s',
    self::COMBINE => '%1$s ( %2$s )',
    self::ORDER  => array(...),
    self::LIMIT  => 'LIMIT %1$s',
    self::OFFSET => 'OFFSET %1$s',
);

I just moved ORDER, LIMIT, and OFFSET to the end. This fixed the query for me.



来源:https://stackoverflow.com/questions/18961207/zf2-union-pagination

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!