@regex29

Как сделать min() по join таблице в построителе запросов?

Как сделать min() по join таблице в построителе запросов yii2?
Пробую такой вариант, но в employee возвращает пустой массив.
return Department::find()->joinWith(['employee'])
    ->select('MIN(employee.salary) AS minSalary, name, department.image')
    ->groupBy('department.id')
    ->all();

или как правильно преобразовать такой sql запрос в activerecord?
SELECT department.*, MIN(employee.salary ) AS minSalary 
    FROM `department` 
    INNER JOIN employee ON department.id = employee.employeeId
    GROUP BY department.id;
  • Вопрос задан
  • 85 просмотров
Решения вопроса 1
vilinyh
@vilinyh
Смысл Department::find() в том, что вы выбираете модели Department, а не агрегаты в смежных таблицах. В модели Department нет атрибута minSalary, он туда не загрузится при формировании моделей.

Если нужен именно minSalary в модели, создайте отдельный класс:

class DepartmentWithSalary extends Department
{
    public $minSalary;
}

// ...

/** @var DepartmentWithSalary[] $deps */
$deps = DepartmentWithSalary::find()
    ->alias('d')
    ->innerJoinWith('employee e')
    ->select('d.*')
    ->addSelect(['minSalary' => 'min(e.salary)'])
    ->groupBy('d.id')
    ->all();

Как замечено в комментариях, запрос incomplete grouping, поэтому работать будет только на MySQL с выключенным ONLY_FULL_GROUP_BY и при прокинутых PK/FK.

Если модели не нужны, а достаточно массива, используйте asArray:

$query = Department::find()
    ->alias('d')
    ->innerJoinWith('employee e')
    ->select([
        'id' => 'd.id',
        'minSalary' => 'min(e.salary)',
    ])
    ->groupBy('d.id');

// SELECT `d`.`id` AS `id`, min(e.salary) AS `minSalary`
// FROM `department` `d`
// INNER JOIN `employee` `e` ON `d`.`id` = `e`.`departmentId`
// GROUP BY `d`.`id`

/** @var array $deps */
$deps = $query->asArray()->all();
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@Miron11
Пишу sql 20 лет. Срок :)
SQL
---
select department.*
         , coalesce(dptSlr.minSalary, 0.00) as minSalary
FROM `department` 
left outer join 
(SELECT employee.departmentId, MIN(employee.salary ) AS minSalary 
    FROM employee
    GROUP BY employee.departmentId) dptSlr
on department.id = dptSlr.departmentId;
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы