YII2 построение запроса ActiveQuery
Нужна помощь в построение запроса ActiveQuery. Я уже 3 дня ломаю голову, но видимо моих знаний не достаточно.
Есть 2 таблицы:
- clients (
client_id,
client_title,
client_type
.....)
- client_details (
row_id,
detail_client_id,
detail_type,
detail_value,
....)
Связи:
public function getClientDetails()
{
return $this->hasMany(ClientDetail::class, ['detail_client_id' => 'client_id']);
}
public function getClient()
{
return $this->hasOne(Client::class, ['client_id' => 'detail_client_id']);
}
В таблице clients хранятся клиенты с различными типами (нас интересуют тип 5 и 6). В таблице client_details хранятся характеристики этих клиентов (не ограниченное количество).
Связь между клиентами разных типов 5(юр. лица) и 6(договора) следующая. У клиента с типом 5 (из таблици clients) есть записи (несколько) в таблице client_details где detail_type =111 а detail_value-ЭТО НОМЕР ДОГОВОРА. У клиента с типом 6 (из таблици clients) есть одна запись в таблице client_details где detail_type =86 а detail_value-ЭТО НОМЕР ДОГОВОРА.
Как построить activerecord запрос в ClientSearch чтобы получить все записи из таблицы clients с типом 6 (с данными некоторых характеристик из таблицы client_details) и к ним притянуть client_title из таблицы clients с типом 5. Т.е. у меня есть список договором, мне нужно вывести его в GridView с определенными характеристиками и названием юр. лица.
Сейчас есть такой запрос:
$query = LegalEntity::find()->alias('c')
->joinWith([
'clientDetails cd' => static function (ActiveQuery $query) {
$query->andOnCondition(['cd.detail_type' => DetailType::TYPE_LEGAL_ENTITY_ADDRESS]);
$query->andOnCondition(['cd.detail_status' => Detail::STATUS_ACTIVE]);
}
])
->andFilterWhere([
'c.client_type' => $this->validationRange
]);
$this->load($params);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 50
]
]);
Так получаю все заказы с характеристиками. А название юр. лица вытягиваю отдельным методом, непосредственно в GridView. Но это не позволяет фильтровать по юр. лицу и плодит много дополнительных запросов к БД.
Вот как выглядит SQL запрос:
SELECT clients.client_id,
clients.client_title,
clients.client_type,
(select cd.detail_value
from client_details cd
where cd.detail_type = 41
AND cd.detail_client_id = client_id
AND cd.detail_status = 1
LIMIT 1
) AS address,
(select cd.detail_value
from client_details cd
where cd.detail_type = 9
AND cd.detail_client_id = client_id
AND cd.detail_status = 1
ORDER BY cd.row_id DESC
LIMIT 1
) AS fias,
(select cd.detail_value
from client_details cd
where cd.detail_type = (CASE
WHEN client_type = 6
THEN 6
WHEN client_type = 7
THEN 86
END)
AND cd.detail_client_id = client_id
AND cd.detail_status = 1
LIMIT 1
) AS bgb,
(SELECT cl.client_title
FROM clients cl
JOIN client_details cd ON cd.detail_client_id = cl.client_id
WHERE
cd.detail_type = 111 AND
cd.detail_value = bgb
GROUP BY cl.client_title
LIMIT 1
) AS name
FROM clients
LEFT JOIN client_details ON client_details.detail_client_id = clients.client_id
WHERE
(clients.client_type = 6 OR clients.client_type = 7)
AND
clients.client_status = 1
GROUP BY clients.client_title
Ответы (1 шт):
Вот какой запрос получился, может кому-то пригодится.
$query = LegalEntity::find()->alias('c')
->select(['c.client_id', 'c.client_title', 'c.client_type',
'address' => 'cda.detail_value',
'fias' => 'cdf.detail_value',
'bgb' => 'cdb.detail_value',
'nameid' => 'cdcl.detail_client_id',
'name' => 'cl.client_title',
])
->leftJoin(['cda' => 'client_details'],
[
'and',
['cda.detail_client_id' => new Expression('c.client_id')],
['cda.detail_type' => DetailType::TYPE_LEGAL_ENTITY_ADDRESS],
['cda.detail_status' => Detail::STATUS_ACTIVE],
]
)
->leftJoin(['cdf' => 'client_details'],
[
'and',
['cdf.detail_client_id' => new Expression('c.client_id')],
['cdf.detail_type' => DetailType::TYPE_FIAS],
['cdf.detail_status' => Detail::STATUS_ACTIVE],
]
)
->leftJoin(['cdb' => 'client_details'],
[
'and',
['cdb.detail_client_id' => new Expression('c.client_id')],
['cdb.detail_type' => new Expression('CASE WHEN c.client_type = 6 THEN 6 WHEN c.client_type = 7 THEN 86 END')],
['cdb.detail_status' => Detail::STATUS_ACTIVE],
]
)
->leftJoin(['cdcl' => 'client_details'],
[
'and',
['cdcl.detail_type' => DetailType::TYPE_SUBCONTRACT],
['cdcl.detail_value' => new Expression('cdb.detail_value')],
['cdb.detail_status' => Detail::STATUS_ACTIVE],
]
)
->leftJoin(['cl' => 'clients'],
[
'and',
['cl.client_type' => ClientTypeList::TYPE_LEGAL_ENTITIES],
['cl.client_id' => new Expression('cdcl.detail_client_id')],
['cl.client_status' => Detail::STATUS_ACTIVE],
]
)
->andWhere(['c.client_status' => Detail::STATUS_ACTIVE])
->andFilterWhere([
'c.client_type' => $this->validationRange
]);
где
DetailType::TYPE_LEGAL_ENTITY_ADDRESS = 41
DetailType::TYPE_FIAS = 9
DetailType::TYPE_SUBCONTRACT = 111
Detail::STATUS_ACTIVE = 1
$this->validationRange = [6, 7]