How do you modify a UNION query in CakePHP 3? -


i want paginate union query in cakephp 3.0.0. using custom finder, have working almost perfectly, can't find way limit , offset apply union, rather either of subqueries.

in other words, code:

$articlesquery = $articles->find('all'); $commentsquery = $comments->find('all'); $unionquery = $articlesquery->unionall($commentsquery); $unionquery->limit(7)->offset(7); // nevermind weirdness of applying manually 

produces query:

(select {article stuff} order created desc limit 7 offset 7) union  (select {comment stuff})  

instead of want, this:

(select {article stuff}) union  (select {comment stuff}) order created desc limit 7 offset 7 

i could manually construct correct query string this:

$unionquery = $articlesquery->unionall($commentsquery); $sql = $unionquery->sql(); $sql = "($sql) order created desc limit 7 offset 7"; 

but custom finder method needs return \cake\database\query object, not string.

so,

  • is there way apply methods limit() entire union query?
  • if not, there way convert sql query string query object?

note: there's a closed issue describes similar (except using paginate($unionquery)) without suggestion of how overcome problem.

apply limit , offset each subquery?

scrowler kindly suggested option, think won't work. if limit set 5 , full result set this:

article 9     --| article 8       | article 7       -- page 1 article 6       | article 5     --|  article 4     --| comment 123     | article 3       -- here dragons comment 122     | comment 121   --| ... 

then query page 1 work, because (the first 5 articles) + (the first 5 comments), sorted manually date, , trimmed first 5 of combined result result in articles 1-5.

but page 2 won't work, because offset of 5 applied both articles , comments, meaning first 5 comments (which weren't included in page 1), never show in results.

being able apply these clauses directly on query returned unionall() not possible afaik, require changes api make compiler aware put sql, being via options, new type of query object, whatever.

query::epilog() rescue

luckily it's possible append sql queries using query::epilog(), being raw sql fragments

$unionquery->epilog('order created desc limit 7 offset 7'); 

or query expressions

$unionquery->epilog(     $connection->newquery()->order(['created' => 'desc'])->limit(7)->offset(7) ); 

this should give desired query.

it should noted according docs query::epilog() expects either string, or concrete \cake\database\expressioninterface implementation in form \cake\database\expression\queryexpression instance, not any expressioninterface implementation, theoretically latter example invalid, though query compiler works expressioninterface implementation.

use subquery

it's possible utilize union query subquery, make things easier in context of using pagination component, wouldn't have take care of other building , injecting subquery, since paginator component able apply order/limit/offset on 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 of course moved finder.


Comments

Popular posts from this blog

javascript - AngularJS custom datepicker directive -

javascript - jQuery date picker - Disable dates after the selection from the first date picker -