Yii2 MySQL 按关系计数排序


Yii2 MySQL Order By Relation Count

表 1 - 用户:

ID Name
1 Jonh
2 Mark
3 King


表2 - 书籍:

ID user_id status ...
1 1 1 ...
2 1 1 ...
3 1 1 ...
4 2 1 ...
5 1 0 ...
6 1 0 ...


法典:

$query = User::find();
$query->joinWith('books');
$query->select(['user.*', 'COUNT(book.id) AS booksCount']);
$query->andWhere(['book.status' => 1]); // Problem Here!
$query->groupBy(['user.id']);
$query->orderBy(['booksCount' => SORT_DESC]);

问题:

query工作正常,但未向用户返回id = 3。如果我删除该行$query->andWhere(['book.status' => 1]);它工作正常并返回所有用户。

我应该更改什么以列出所有用户,即使是那些没有与status = 1相关书籍的用户?

我找到了答案:

$query = User::find();
$query->joinWith(['books' => function ($subquery) {
    $subquery->onCondition(['book.status' => 1]);
}]);
$query->select(['user.*', 'COUNT(book.id) AS booksCount']);
$query->groupBy(['user.id']);
$query->orderBy(['booksCount' => SORT_DESC]);

如果书籍的状态为 0 或 1,则可以使用 SUM(book.status) 来获取用户拥有的书籍数量,而不是使用 COUNT(book.id)。然后,您可以删除 WHERE book.status = 1 子句,它将返回所有用户及其拥有的书籍数量,即使在用户 3 的情况下,他们有 0 本书。

问题所在

真正的问题在于您的 where 子句。因为WHERE是在分组之前处理的,而用户 3 没有任何行where book.status = 1,所以用户没有包含在基本查询中的行。因此,用户在分组期间/之后不在场。

如果你想对一个可以根据条件计算行数的包罗万象的情况有一个很好的主意,使用 COUNT(CASE WHEN book.status IS NULL THEN NULL ELSE NULLIF(0,book.status) END) 也会给你你想要的结果。因为COUNT()不会对表达式NULL的行进行计数,这将允许book.status为 -1、1、2 和任何其他数字,只要它不是 0(或用户 3 的情况下为 NULL),并且仍然包含在计数中。