@ugin_root

Как выполнить подзапрос в Doctrine DQL?

Нужно выполнить сложный запрос в Doctrine, но не получается по тому как выходит вот такая ошибка:
[Semantical Error] line 0, col 549 near 'FROM (': Error: Subquery is not supported here


Вот DQL запрос:
SELECT SUM(t.absentDay) AS absentDayAll
FROM (
	SELECT COUNT(DISTINCT DATE_FORMAT(voting.dateAt, '%Y-%m-%d')) AS absentDayHuman
	FROM \App\Entity\Vote vote
		JOIN vote.human human
		JOIN vote.voting voting
		JOIN human.party party
	WHERE vote.type = 0
	GROUP BY human.id
) AS t


Вот аналогичный запрос на SQL:
SELECT SUM(t.absentDay) as absentDayAll
FROM (
		SELECT COUNT(DISTINCT DATE_FORMAT(voting.date_at, '%Y-%m-%d')) AS absentDayHuman
		FROM vote 
				JOIN human ON human.id = vote.human_id
				JOIN voting ON voting.id = vote.voting_id
				JOIN party ON party.id = human.party_id
		WHERE vote.type = 0
		GROUP BY human.id
) AS t


И Docrtine Native Query не подойдёт т.к. этот запрос(и подобные ему) предполагается добавлять как одно из полей к более сложным запросам:
$parties = $partyRepository->createQueryBuilder('party')
	->addSelect("(
		SELECT SUM(q3_absent.absentDay)
		FROM (
			SELECT COUNT(DISTINCT DATE_FORMAT(q3_voting.dateAt, '%Y-%m-%d')) AS absentDay
			FROM " . Vote::class . " q3_vote
				JOIN q3_vote.human q3_human
				JOIN q3_vote.voting q3_voting
				JOIN q3_human.party q3_party
			WHERE vote.type = :typeAbsent AND q3_party.id = party.id
			GROUP BY human.id
		) AS q3_absent
	) AS countAbsentDay")
	->setParameter('typeAbsent', Vote::TYPES_CODE[Vote::TYPE_ABSENT])
	->getQuery()
	->getResult()
;
  • Вопрос задан
  • 2660 просмотров
Решения вопроса 1
Melkij
@Melkij
PostgreSQL DBA
Тупая доктрина не умеет подзапросы в from.

И более того, вовсе не собираются реализовывать.
Используйте нормальный SQL.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@ugin_root Автор вопроса
Печально... Но я вроде додумался до решения для моего частного случая когда нужно посчитать сумму уникальных записей сразу по нескольким полям.
SQL:
SELECT COUNT(DISTINCT 
	YEAR(voting.date_at), 
	MONTH(voting.date_at), 
	DAY(voting.date_at), 
	human.id
) AS absentDayHuman
FROM vote 
	JOIN human ON human.id = vote.human_id
	JOIN voting ON voting.id = vote.voting_id
	JOIN party ON party.id = human.party_id
WHERE vote.type = 0

DQL(в count нельзя указывать несколько параметров):
SELECT COUNT(DISTINCT CONCAT(
	DATE_FORMAT(voting.dateAt, '%Y-%m-%d'), 
	'-', 
	human.id
)) AS absent
FROM \App\Entity\Vote vote
	JOIN vote.human human
	JOIN vote.voting voting
	JOIN human.party party
WHERE vote.type = :voteTypeAbsent
Ответ написан
Комментировать
@warmic
Доктрина,конечно,не очень хороша в подзапросах,однако выход есть

Пример
$subDQL = $this->getEntityManager()->createQueryBuilder()
->select('c.p_id')
->from(SomeClass::class, 'c')
->where((new Expr())->in('c.status', [
'a', 'b'
]))
->andWhere('c.date >= :dateFrom')
->distinct();

$mainDQL = $this->createQueryBuilder('p')
->select('p')
->where((new Expr())->in('p.id', $subDQL->getDQL()))
->setParameter('dateFrom', $dateFrom)
->orderBy('p.tdsId', Criteria::ASC);
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы