🙂
Заранее благодарю вас за помощь в решении этой проблемы:
У меня есть компания, имеющая отношение ManyToMany к сущности HotelService
как я могу построить (с QueryBuilder, если возможно) один запрос, чтобы выбрать все отели с подмножеством услуг, заданными как параметр массива?
Пример: H1 (S1, S2, S3, S4), H2 (S2, S3, S4), H3 (S1, S2, S3)
Запрос с подмножеством (S1, S2) должен возвращать H1 и H3.
Я пробовал много вещей, это какой-то фрагмент кода:
public function findByServices($services) { $qb = $this->createQueryBuilder('hotel') ->addSelect('location') ->addSelect('country') ->addSelect('billing') ->addSelect('services') ->innerJoin('hotel.billing', 'billing') ->innerJoin('hotel.location', 'location') ->innerJoin('location.city', 'city') ->innerJoin('location.country', 'country'); ->innerJoin('hotel.services', 'services'); $i = 0; $arrayIds = array(); foreach ($services as $service) { $arrayIds[$i++] = $service->getId(); } $qb->add('where', $qb->expr()->in('services', $arrayIds))->getQuery(); }
Этот код возвращает все отели, для которых есть один идентификатор службы в $ arrayIds.
Я хочу наоборот (гостиницы, для которых сервисы содержат ВСЕ идентификаторы в $ arrayIds).
Конечно, инверсные параметры в expr () -> in не решают проблему и создают ошибки с плохими параметрами.
Может кто-нибудь мне помочь? (Извините за мой плохой английский) 🙂
Для вашего решения вы можете использовать COUNT(DISTINCT)
с предложениями HAVING
и GROUP BY
public function findByServices($services) { $qb = $this->createQueryBuilder('hotel') ->addSelect('location') ->addSelect('country') ->addSelect('billing') ->addSelect('services') ->addSelect('COUNT(DISTINCT services.id) AS total_services') ->innerJoin('hotel.billing', 'billing') ->innerJoin('hotel.location', 'location') ->innerJoin('location.city', 'city') ->innerJoin('location.country', 'country') ->innerJoin('hotel.services', 'services'); $i = 0; $arrayIds = array(); foreach ($services as $service) { $arrayIds[$i++] = $service->getId(); } $qb->add('where', $qb->expr()->in('services', $arrayIds)) ->addGroupBy('hotel.id') ->having('total_services = '.count($arrayIds)) ->getQuery(); }
В вышеприведенном запросе я добавил еще один выбор как подсчет различных идентификаторов службы для каждого отеля, т.е.
-> addSelect ('COUNT (DISTINCT services.id) AS HIDDEN total_services')
Тогда мне также нужна группа для этого счета, поэтому я добавил
-> addGroupBy ( 'hotel.id')
Теперь здесь идет сложная часть, поскольку вы упомянули, что вам нужна гостиница, в которой есть все идентификаторы службы, такие как идентификаторы (1,2,3), поэтому отели, которые содержат эти 3 службы, должны быть возвращены, когда мы используем их в своих действиях или работе, например, where servid_id = 1 or servid_id = 2 servid_id = 3
что именно вы не хотите, чтобы операция AND
имела эти 3, поэтому я решил эту логику,
-> having ('total_services =' .count ($ arrayIds))
Теперь total_services
является виртуальным псевдонимом для запроса и содержит определенное количество баллов для каждого отеля, поэтому я сравнил этот счет с количеством предоставленных идентификаторов в части IN()
это вернет отели, которые должны содержать эти услуги
GROUP BY and HAVING Clause