Skip to content

Commit

Permalink
Support UNION aggregate queries (#26365)
Browse files Browse the repository at this point in the history
  • Loading branch information
staudenmeir authored and taylorotwell committed Nov 4, 2018
1 parent bdfc993 commit 9c737f8
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/Illuminate/Database/Query/Grammars/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ class Grammar extends BaseGrammar
*/
public function compileSelect(Builder $query)
{
if ($query->unions && $query->aggregate) {
return $this->compileUnionAggregate($query);
}

// If the query does not have any columns set, we'll set the columns to the
// * character to just get all of the columns from the database. Then we
// can build the query and concatenate all the pieces together as one.
Expand Down Expand Up @@ -735,6 +739,21 @@ protected function compileUnion(array $union)
return $conjunction.$union['query']->toSql();
}

/**
* Compile a union aggregate query into SQL.
*
* @param \Illuminate\Database\Query\Builder $query
* @return string
*/
protected function compileUnionAggregate(Builder $query)
{
$sql = $this->compileAggregate($query, $query->aggregate);

$query->aggregate = null;

return $sql.' from ('.$this->compileSelect($query).') as '.$this->wrapTable('temp_table');
}

/**
* Compile an exists statement into SQL.
*
Expand Down
4 changes: 4 additions & 0 deletions src/Illuminate/Database/Query/Grammars/MySqlGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class MySqlGrammar extends Grammar
*/
public function compileSelect(Builder $query)
{
if ($query->unions && $query->aggregate) {
return $this->compileUnionAggregate($query);
}

$sql = parent::compileSelect($query);

if ($query->unions) {
Expand Down
4 changes: 4 additions & 0 deletions src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ class SQLiteGrammar extends Grammar
*/
public function compileSelect(Builder $query)
{
if ($query->unions && $query->aggregate) {
return $this->compileUnionAggregate($query);
}

$sql = parent::compileSelect($query);

if ($query->unions) {
Expand Down
27 changes: 27 additions & 0 deletions tests/Database/DatabaseQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,33 @@ public function testMySqlUnionLimitsAndOffsets()
$this->assertEquals('(select * from `users`) union (select * from `dogs`) limit 10 offset 5', $builder->toSql());
}

public function testUnionAggregate()
{
$expected = 'select count(*) as aggregate from ((select * from `posts`) union (select * from `videos`)) as `temp_table`';
$builder = $this->getMySqlBuilder();
$builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true);
$builder->getProcessor()->shouldReceive('processSelect')->once();
$builder->from('posts')->union($this->getMySqlBuilder()->from('videos'))->count();

$expected = 'select count(*) as aggregate from (select * from "posts" union select * from "videos") as "temp_table"';
$builder = $this->getPostgresBuilder();
$builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true);
$builder->getProcessor()->shouldReceive('processSelect')->once();
$builder->from('posts')->union($this->getPostgresBuilder()->from('videos'))->count();

$expected = 'select count(*) as aggregate from (select * from (select * from "posts") union select * from (select * from "videos")) as "temp_table"';
$builder = $this->getSQLiteBuilder();
$builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true);
$builder->getProcessor()->shouldReceive('processSelect')->once();
$builder->from('posts')->union($this->getSQLiteBuilder()->from('videos'))->count();

$expected = 'select count(*) as aggregate from (select * from [posts] union select * from [videos]) as [temp_table]';
$builder = $this->getSqlServerBuilder();
$builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true);
$builder->getProcessor()->shouldReceive('processSelect')->once();
$builder->from('posts')->union($this->getSqlServerBuilder()->from('videos'))->count();
}

public function testSubSelectWhereIns()
{
$builder = $this->getBuilder();
Expand Down

0 comments on commit 9c737f8

Please sign in to comment.