Получить сумму столбца в связанной таблице - PullRequest
0 голосов
/ 27 апреля 2018

SETUP

У меня есть следующие настройки БД:

// Contacts
,----,--------,---------,----------,
| id | name   | surname | is_agent |
|----|--------|---------|----------|
| 1  | Jhon   | Doe     | Yes      |
'----'--------'---------'----------'

// ContactAttributes
,----,------------------,
| id | own_transport    |
|----|------------------|
| 1  | Yes              |
'----'------------------'

// Reviews
,----,------------,-------------,--------,
| id | contact_id | reviewed_by | rating |
|----|------------|-------------|--------|
| 1  | 1          | 7           | 5      |
| 2  | 1          | 5           | 3      |
| 3  | 1          | 4           | 4      |
'----'------------'-------------'--------'

Контакты имеют отношение один к одному ContactAttributes и один ко многим с Отзывы. Просматривается также ссылки на контакты, но только для получения имени и фамилии.

ЧТО ХОЧУ

Я хочу получить сумму оценок за контакт. Поэтому, если я потяну контакт 1, я хочу видеть review_total как 12.

ЧТО Я ПОПЫТАЛ

Из документов Я вижу, что мне нужно построить свой запрос следующим образом:

$query = $contactsTable->find();
$query->select(['review_sum' => $query->func()->sum('Reviews.rating')])
    ->where([
        'Contacts.is_agent' => 'no',
        'ContactAttributes.own_transport' => 'Yes',
    ])
    ->contain(['ContactAttributes', 'Reviews'])
    ->first();

ПРОБЛЕМА

Я получаю эту ошибку при запуске выше:

Error: SQLSTATE[42P01]: Undefined table: 7 ERROR: missing FROM-clause entry for table "reviews" LINE 1: SELECT (SUM(Reviews.rating)) AS "review_sum" FROM contacts C... ^

И этот запрос он пытается выполнить:

SELECT (SUM(Reviews.rating)) AS "review_sum" FROM contacts Contacts LEFT JOIN contact_attributes ContactAttributes ON Contacts.id = (ContactAttributes.id) WHERE (Contacts.is_agent = :c0 AND ContactAttributes.own_transport = :c1) LIMIT 1

ВОПРОС

Как я могу решить это? Что я делаю не так или есть более простой способ сделать это?

РЕДАКТИРОВАТЬ 1

У меня это работает так, но должен быть более подход CakePHP.

$contactsTable->find()
    ->select([
        'Contacts.id',
        'Contacts.firstname',
        'Users.username',
        'Contacts.lastname',
        'Contacts.id_number',
        'Contacts.coordinates',
        'review_sum' => 'SUM(reviews.rating)'
    ])
    ->leftJoin(['Reviews' => 'reviews'], 'Reviews.contact_id = Contacts.id')
    ->leftJoin(['Users' => 'users'], 'Users.id = Contacts.id')
    ->leftJoin(['ContactAttributes' => 'contact_attributes'], 'ContactAttributes.id = Contacts.id')
    ->where([
        'Contacts.is_agent' => 'no',
        'ContactAttributes.own_transport' => $job->own_transport
    ])
    ->orderDesc('review_sum')
    ->group('Users.username')
    ->group('Contacts.id')
    ->having(['SUM(Reviews.rating) IS NOT NULL']);

Ответы [ 3 ]

0 голосов
/ 28 апреля 2018

Похоже, что в тот момент, когда вы делаете сумму, $ query только частично инициализируется одной таблицей. Попробуйте заменить первую строку этим.

$query = $contactsTable->find()->contain(['ContactAttributes', 'Reviews']);

и удалите строку содержания в конце.

0 голосов
/ 30 апреля 2018

Так как у вас есть отношение ownToMany, вы должны поместить функцию внутри вызова Contain

$query
    ->where([
        'Contacts.is_agent' => 'no',
        'ContactAttributes.own_transport' => 'Yes',
    ])
    ->contain([
        'ContactAttributes', 
        'Reviews' => function($q) {
            $q->select([
                'review_sum' => $query->func()->sum('Reviews.rating') 
                ])
            ->group(['contact_id'])
    }])
->first();
0 голосов
/ 27 апреля 2018

Я думаю, что в вашем запросе отсутствует JOIN. У вас есть контакты и контактные атрибуты, но нет отзывов. Вам нужно добавить что-то вроде этого.

LEFT JOIN Reviews ON Contacts.id = Reviews.contact_id
...