How do you modify a UNION query in CakePHP 3?

最后都变了- 提交于 2019-11-28 12:21:25

Being able to apply these clauses directly on the query returned by unionAll() is not possible AFAIK, it would require changes to the API that would make the compiler aware where to put the SQL, being it via options, a new type of query object, whatever.

Query::epilog() to the rescue

Luckily it's possible to append SQL to queries using Query::epilog(), being it raw SQL fragments

$unionQuery->epilog('ORDER BY created DESC LIMIT 7 OFFSET 7');

or query expressions

$unionQuery->epilog(
    $connection->newQuery()->order(['created' => 'DESC'])->limit(7)->offset(7)
);

This should give you the desired query.

It should be noted that according to the docs Query::epilog() expects either a string, or a concrete \Cake\Database\ExpressionInterface implementation in the form a \Cake\Database\Expression\QueryExpression instance, not just any ExpressionInterface implementation, so theoretically the latter example is invalid, even though the query compiler works with any ExpressionInterface implementation.

Use a subquery

It's also possible to utilize the union query as a subquery, this would make things easier in the context of using the pagination component, as you wouldn't have to take care of anything other than building and injecting the subquery, since the paginator component would be able to simply apply the order/limit/offset on the main query.

/* @var $connection \Cake\Database\Connection */
$connection = $articles->connection();

$articlesQuery = $connection
    ->newQuery()
    ->select(['*'])
    ->from('articles');

$commentsQuery = $connection
    ->newQuery()
    ->select(['*'])
    ->from('comments');

$unionQuery = $articlesQuery->unionAll($commentsQuery);

$paginatableQuery = $articles
    ->find()
    ->from([$articles->alias() => $unionQuery]);

This could of course also be moved into a finder.

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