Выбрать записи у которых есть только указанные связи

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Выбрать записи у которых есть только указанные связи

Сообщение edvardpotter »

Добрый день, не подскажите как сделать select, который будет выбирать записи у которых обязательно есть только указанные связи?
В данный момент сделано так: если я указал [1,2,3] и у одной из моделей несколько связей(например: 1,2,3), а у другой (1,2,3,5) то in выберет обе записи.

Код: Выделить всё

<?php
$query
    ->joinWith('modes')
    ->joinWith('styles')
    ->andFilterWhere([
        'id' => $this->id,
        'players.game_id' => $this->game_id,
        'user_id' => $this->user_id,
        'style.id' => $this->search_styles,
        'modes.id' => $this->search_modes,
    ]);
?>
BalykhinAS
Сообщения: 179
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Выбрать записи у которых есть только указанные связи

Сообщение BalykhinAS »

edvardpotter писал(а): 2018.03.06, 11:15 Добрый день, не подскажите как сделать select, который будет выбирать записи у которых обязательно есть только указанные связи?
В данный момент сделано так: если я указал [1,2,3] и у одной из моделей несколько связей(например: 1,2,3), а у другой (1,2,3,5) то in выберет обе записи.

Код: Выделить всё

<?php
$query
    ->joinWith('modes')
    ->joinWith('styles')
    ->andFilterWhere([
        'id' => $this->id,
        'players.game_id' => $this->game_id,
        'user_id' => $this->user_id,
        'style.id' => $this->search_styles,
        'modes.id' => $this->search_modes,
    ]);
?>
лучше напишите запрос который в итоге хотите получить
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Выбрать записи у которых есть только указанные связи

Сообщение edvardpotter »

Wizard писал(а): 2018.03.06, 11:20 лучше напишите запрос который в итоге хотите получить
В том то и дело что я не могу составить такой запрос даже на чистом SQL. Есть такой вариант но там для связи один-ко-многим, а у меня связь многие-ко-многим.
BalykhinAS
Сообщения: 179
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Выбрать записи у которых есть только указанные связи

Сообщение BalykhinAS »

edvardpotter писал(а): 2018.03.06, 11:15 В данный момент сделано так: если я указал [1,2,3] и у одной из моделей несколько связей(например: 1,2,3), а у другой (1,2,3,5) то in выберет обе записи.
то есть согласно условию в выборку должна попасть только первый объект у которого 1,2,3 а второй проигнорировать?

сложно сказать без примера запроса но скорее всего надо смотреть в сторону Having
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Выбрать записи у которых есть только указанные связи

Сообщение edvardpotter »

Wizard писал(а): 2018.03.06, 17:02 то есть согласно условию в выборку должна попасть только первый объект у которого 1,2,3 а второй проигнорировать?
Да, именно так.
Wizard писал(а): 2018.03.06, 17:02 скорее всего надо смотреть в сторону Having
В том вопросе having и используется, т.е. примерный запрос должен быть таким:

Код: Выделить всё

SELECT DISTINCT
    p.*
FROM
    `players` AS p
LEFT JOIN `players_modes` AS pm
ON
    p.`id` = pm.`player_id`
LEFT JOIN `modes` AS m
ON
    pm.`mode_id` = m.`id`
LEFT JOIN `players_styles` AS ps
ON
    p.`id` = ps.`player_id`
LEFT JOIN `style` AS s
ON
    ps.`style_id` = s.`id`
WHERE
    (p.`game_id` = '3') AND(s.`id` IN('3', '4', '5'))
HAVING
    COUNT(/*кол-во связей*/) = 3
Только не могу теперь понять как получить кол-во связей.
BalykhinAS
Сообщения: 179
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Выбрать записи у которых есть только указанные связи

Сообщение BalykhinAS »

не уверен что верно отследил зависимости в вашем запросе но можете проверить голым запросом

Код: Выделить всё

p.player_id in (
   SELECT ps.player_id 
   FROM style s
   LEFT JOIN players_styles ps 
   WHERE s.id in('3', '4', '5') 
   GROUP BY ps.player_id 
   HAVING COUNT(*)=3
)
еще в вашем запросе нет GROUP BY
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Выбрать записи у которых есть только указанные связи

Сообщение edvardpotter »

Wizard писал(а): 2018.03.06, 17:23 не уверен что верно отследил зависимости в вашем запросе но можете проверить голым запросом

Код: Выделить всё

p.player_id in (
   SELECT ps.player_id 
   FROM style s
   LEFT JOIN players_styles ps 
   WHERE s.id in('3', '4', '5') 
   GROUP BY ps.player_id 
   HAVING COUNT(*)=3
)
еще в вашем запросе нет GROUP BY
Этот селект в каждом запросе будет выполняться, слишком затратно.
BalykhinAS
Сообщения: 179
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Выбрать записи у которых есть только указанные связи

Сообщение BalykhinAS »

попробуйте убрать лишние связи и оставить только style и players_styles добавьте GROUP BY - у себя проверил, все сработало

пс
и players_styles есть style_id потому достаточно оставить одну связь

в итоге получится что то подобное

Код: Выделить всё

SELECT p.*
FROM players AS p
INNER JOIN players_styles ps ON p.id ps.player_id
WHERE p.game_id = '3' AND ps.style_id IN('3', '4', '5')
GROUP BY p.id HAVING COUNT(*) = 3
должно отработать верно
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Выбрать записи у которых есть только указанные связи

Сообщение edvardpotter »

Wizard писал(а): 2018.03.06, 17:59 попробуйте убрать лишние связи и оставить только style и players_styles добавьте GROUP BY - у себя проверил, все сработало

пс
и players_styles есть style_id потому достаточно оставить одну связь

в итоге получится что то подобное

Код: Выделить всё

SELECT p.*
FROM players AS p
INNER JOIN players_styles ps ON p.id ps.player_id
WHERE p.game_id = '3' AND ps.style_id IN('3', '4', '5')
GROUP BY p.id HAVING COUNT(*) = 3
должно отработать верно
Да, проверил - работает. Но остальные то джойны обязательны)
BalykhinAS
Сообщения: 179
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Выбрать записи у которых есть только указанные связи

Сообщение BalykhinAS »

edvardpotter писал(а): 2018.03.06, 18:31
Wizard писал(а): 2018.03.06, 17:59 попробуйте убрать лишние связи и оставить только style и players_styles добавьте GROUP BY - у себя проверил, все сработало

пс
и players_styles есть style_id потому достаточно оставить одну связь

в итоге получится что то подобное

Код: Выделить всё

SELECT p.*
FROM players AS p
INNER JOIN players_styles ps ON p.id ps.player_id
WHERE p.game_id = '3' AND ps.style_id IN('3', '4', '5')
GROUP BY p.id HAVING COUNT(*) = 3
должно отработать верно
Да, проверил - работает. Но остальные то джойны обязательны)
я исходил из приведенного запроса, не увидел в них необходимости :)
BalykhinAS
Сообщения: 179
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Выбрать записи у которых есть только указанные связи

Сообщение BalykhinAS »

каждый join дублирует запись, если это возможно то попробуйте высчитать количество соответствий в HAVING ели нет то только подзапрос в in(...)
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Выбрать записи у которых есть только указанные связи

Сообщение edvardpotter »

Посоветовали такой вариант, только как это теперь транслировать в yii

Код: Выделить всё

SELECT     `players`.*
FROM       `players`
INNER JOIN `players_styles` ON `players`.`id` = `players_styles`.`player_id`
INNER JOIN `style` ON `players_styles`.`style_id` = `style`.`id`
LEFT  JOIN `players_modes` ON `players`.`id` = `players_modes`.`player_id`
LEFT  JOIN `modes` ON `players_modes`.`mode_id` = `modes`.`id`
WHERE      `players`.`game_id` = '3' 
GROUP BY   `players`.`id`
HAVING     SUM(`style`.`id` NOT IN ('3', '4', '5')) = 0
   AND     COUNT(DISTINCT `style`.`id`) = 3
Сделал все кроме этого

Код: Выделить всё

SUM(`style`.`id` NOT IN ('3', '4', '5')) = 0
BalykhinAS
Сообщения: 179
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Выбрать записи у которых есть только указанные связи

Сообщение BalykhinAS »

edvardpotter писал(а): 2018.03.06, 20:21 Посоветовали такой вариант, только как это теперь транслировать в yii

Код: Выделить всё

SELECT     `players`.*
FROM       `players`
INNER JOIN `players_styles` ON `players`.`id` = `players_styles`.`player_id`
INNER JOIN `style` ON `players_styles`.`style_id` = `style`.`id`
LEFT  JOIN `players_modes` ON `players`.`id` = `players_modes`.`player_id`
LEFT  JOIN `modes` ON `players_modes`.`mode_id` = `modes`.`id`
WHERE      `players`.`game_id` = '3' 
GROUP BY   `players`.`id`
HAVING     SUM(`style`.`id` NOT IN ('3', '4', '5')) = 0
   AND     COUNT(DISTINCT `style`.`id`) = 3
Сделал все кроме этого

Код: Выделить всё

SUM(`style`.`id` NOT IN ('3', '4', '5')) = 0
может все же подзапрос будет проще? тем более подзапрос можно сделать отдельной выборкой и передавать в качестве массива. уж больно страшно выглядет :) не думаю что такие запросы будут легче подзапорса, хотя бы проверьте в phpmyadmin разницу загрузки.
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Выбрать записи у которых есть только указанные связи

Сообщение edvardpotter »

Wizard писал(а): 2018.03.06, 22:02 может все же подзапрос будет проще? тем более подзапрос можно сделать отдельной выборкой и передавать в качестве массива. уж больно страшно выглядет :) не думаю что такие запросы будут легче подзапорса, хотя бы проверьте в phpmyadmin разницу загрузки.
Вообще никакой разницы не заметил, запросы выполняются так же как и с первоначальным вариантом.
andku83
Сообщения: 988
Зарегистрирован: 2016.07.01, 10:24
Откуда: Харьков

Re: Выбрать записи у которых есть только указанные связи

Сообщение andku83 »

edvardpotter писал(а): 2018.03.06, 20:21 Сделал все кроме этого

Код: Выделить всё

SUM(`style`.`id` NOT IN ('3', '4', '5')) = 0
предполагаю что такой вариант будет возвращать записи у которых есть только 1 или 2 связи и вообще не представляю как такое может работать
мне все же кажется что под запрос с IN и проще/понятнее да и быстрее должен быть
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Выбрать записи у которых есть только указанные связи

Сообщение edvardpotter »

shnir писал(а): 2018.03.07, 21:27
edvardpotter писал(а): 2018.03.06, 20:21 Сделал все кроме этого

Код: Выделить всё

SUM(`style`.`id` NOT IN ('3', '4', '5')) = 0
предполагаю что такой вариант будет возвращать записи у которых есть только 1 или 2 связи и вообще не представляю как такое может работать
мне все же кажется что под запрос с IN и проще/понятнее да и быстрее должен быть
Работает то все отлично, тут объяснили как выбираются записи, как это на yii теперь сделать можете подсказать?
andku83
Сообщения: 988
Зарегистрирован: 2016.07.01, 10:24
Откуда: Харьков

Re: Выбрать записи у которых есть только указанные связи

Сообщение andku83 »

Код: Выделить всё

->having(new \yii\db\Expression('SUM(`style`.`id` NOT IN (:range)) = 0', [':range' => $ids]))
попробуйте
edvardpotter
Сообщения: 27
Зарегистрирован: 2017.08.19, 21:40

Re: Выбрать записи у которых есть только указанные связи

Сообщение edvardpotter »

shnir писал(а): 2018.03.09, 14:21

Код: Выделить всё

->having(new \yii\db\Expression('SUM(`style`.`id` NOT IN (:range)) = 0', [':range' => $ids]))
попробуйте
Примерно так и пробовал, в итоге запрос получается такой:

Код: Выделить всё

HAVING (SUM(style.id` NOT IN (NULL)) = 0)
видимо массивы таким образом нельзя передавать
andku83
Сообщения: 988
Зарегистрирован: 2016.07.01, 10:24
Откуда: Харьков

Re: Выбрать записи у которых есть только указанные связи

Сообщение andku83 »

продолжаем думать дальше:

Код: Выделить всё

->having(new \yii\db\Expression('SUM(`style`.`id` NOT IN (:range)) = 0', [':range' => implode(',', $ids)]))
Ответить