Skip to content

Commit

Permalink
Fixed aggregations when group by and having conditions are used (#284)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinMystikJonas authored and dg committed Nov 24, 2021
1 parent fb2476b commit c4df89d
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 14 deletions.
21 changes: 15 additions & 6 deletions src/Database/Table/GroupedSelection.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function order(string $columns, ...$params)
/**
* @return mixed
*/
public function aggregation(string $function)
public function aggregation(string $function, string $groupFunction = null)
{
$aggregation = &$this->getRefTable($refPath)->aggregation[$refPath . $function . $this->sqlBuilder->getSelectQueryHash($this->getPreviousAccessedColumns())];

Expand All @@ -105,12 +105,21 @@ public function aggregation(string $function)

$selection = $this->createSelectionInstance();
$selection->getSqlBuilder()->importConditions($this->getSqlBuilder());
$selection->select($function);
$selection->select("$this->name.$this->column");
$selection->group("$this->name.$this->column");

foreach ($selection as $row) {
$aggregation[$row[$this->column]] = $row;
if ($groupFunction && $selection->getSqlBuilder()->importGroupConditions($this->getSqlBuilder())) {
$selection->select("$function AS aggregate, $this->name.$this->column AS groupname");
$selection->group($selection->getSqlBuilder()->getGroup() . ", $this->name.$this->column");
$query = "SELECT $groupFunction(aggregate) AS groupaggregate, groupname FROM (" . $selection->getSql() . ') AS aggregates GROUP BY groupname';
foreach ($this->context->query($query, ...$selection->getSqlBuilder()->getParameters()) as $row) {
$aggregation[$row->groupname] = $row;
}
} else {
$selection->select($function);
$selection->select("$this->name.$this->column");
$selection->group("$this->name.$this->column");
foreach ($selection as $row) {
$aggregation[$row[$this->column]] = $row;
}
}
}

Expand Down
22 changes: 14 additions & 8 deletions src/Database/Table/Selection.php
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,19 @@ public function alias(string $tableChain, string $alias)
* @param string $function select call in "FUNCTION(column)" format
* @return mixed
*/
public function aggregation(string $function)
public function aggregation(string $function, string $groupFunction = null)
{
$selection = $this->createSelectionInstance();
$selection->getSqlBuilder()->importConditions($this->getSqlBuilder());
$selection->select($function);
foreach ($selection->fetch() as $val) {
return $val;
if ($groupFunction && $selection->getSqlBuilder()->importGroupConditions($this->getSqlBuilder())) {
$selection->select("$function AS aggregate");
$query = "SELECT $groupFunction(aggregate) AS groupaggregate FROM (" . $selection->getSql() . ') AS aggregates';
return $this->context->query($query, ...$selection->getSqlBuilder()->getParameters())->fetch()->groupaggregate;
} else {
$selection->select($function);
foreach ($selection->fetch() as $val) {
return $val;
}
}
}

Expand All @@ -494,7 +500,7 @@ public function count(string $column = null): int
$this->execute();
return count($this->data);
}
return (int) $this->aggregation("COUNT($column)");
return (int) $this->aggregation("COUNT($column)", 'SUM');
}


Expand All @@ -504,7 +510,7 @@ public function count(string $column = null): int
*/
public function min(string $column)
{
return $this->aggregation("MIN($column)");
return $this->aggregation("MIN($column)", 'MIN');
}


Expand All @@ -514,7 +520,7 @@ public function min(string $column)
*/
public function max(string $column)
{
return $this->aggregation("MAX($column)");
return $this->aggregation("MAX($column)", 'MAX');
}


Expand All @@ -524,7 +530,7 @@ public function max(string $column)
*/
public function sum(string $column)
{
return $this->aggregation("SUM($column)");
return $this->aggregation("SUM($column)", 'SUM');
}


Expand Down
13 changes: 13 additions & 0 deletions src/Database/Table/SqlBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,19 @@ public function importConditions(self $builder): void
}


public function importGroupConditions(self $builder): bool
{
if ($builder->having) {
$this->group = $builder->group;
$this->having = $builder->having;
$this->parameters['group'] = $builder->parameters['group'];
$this->parameters['having'] = $builder->parameters['having'];
return true;
}
return false;
}


/********************* SQL selectors ****************d*g**/


Expand Down
51 changes: 51 additions & 0 deletions tests/Database/Explorer/Explorer.aggregation.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,54 @@ test('', function () use ($explorer) {
Assert::count(2, $authors);
Assert::same(2, $authors->count('DISTINCT author.id')); // SELECT COUNT(DISTINCT author.id) FROM `author` INNER JOIN `book` ON `author`.`id` = `book`.`author_id` WHERE (`book`.`translator_id` IS NOT NULL)
});


test('', function () use ($explorer) {
$authors = $explorer->table('book')->group('book.id')->having('COUNT(DISTINCT :book_tag.tag_id) < 2'); // SELECT `author`.* FROM `author` INNER JOIN `book` ON `author`.`id` = `book`.`author_id` WHERE (`book`.`translator_id` IS NOT NULL) GROUP BY `author`.`id`
Assert::count(2, $authors);
Assert::same(2, $authors->count('DISTINCT author.id')); // SELECT COUNT(DISTINCT author.id) FROM `author` INNER JOIN `book` ON `author`.`id` = `book`.`author_id` WHERE (`book`.`translator_id` IS NOT NULL)
});


test('', function () use ($explorer) {
$bookTags = [];
foreach ($explorer->table('book') as $book) {
$book_tags = $book->related('book_tag');
$bookTags[$book->title] = $book_tags->count('DISTINCT tag.id');
}

Assert::same([
'1001 tipu a triku pro PHP' => 2,
'JUSH' => 1,
'Nette' => 1,
'Dibi' => 2,
], $bookTags);
});


test('', function () use ($explorer) {
$bookTags = [];
foreach ($explorer->table('book')->group('book.id, book.title')->having('COUNT(DISTINCT :book_tag.tag_id) < 2') as $book) {
$book_tags = $book->related('book_tag');
$bookTags[$book->title] = $book_tags->count('DISTINCT tag.id');
}

Assert::same([
'JUSH' => 1,
'Nette' => 1,
], $bookTags);
});

test('', function () use ($explorer) {
$bookTags = [];
foreach ($explorer->table('author') as $author) {
$books = $author->related('book');
$bookTags[$author->name] = $books->group('book.id')->having('COUNT(DISTINCT :book_tag.tag_id) < 2')->count('DISTINCT book.id');
}

Assert::same([
'Jakub Vrana' => 1,
'David Grudl' => 1,
'Geek' => 0,
], $bookTags);
});

0 comments on commit c4df89d

Please sign in to comment.