2016-12-22 2 views
0

Я пытаюсь выполнить «сложный» запрос SQL с помощью Doctrine: У меня есть спортивный проект с несколькими делегациями. Я создал события ('e'), чтобы рассказать каждому, что будет дальше.SQL Doctrine: InnerJoin где A.key = B.key или A.key = NULL

Одно событие может быть для нескольких делегаций, и если это для всех, это связано ни с кем (для экономии пространства базы данных) Тогда у меня ManyToMany отношения Разногласия между События и делегаций

И я хотел бы чтобы извлечь все события, которые касаются одной делегации («а») после того, как сейчас (->where('e.startTime > :date')) Это событие связаны при помощи:

->innerJoin('e.delegations', 'd', 'WITH', 'd.name = A') 

Эта работа довольно хорошо, но для события, связанного с не одной делегации она не верните , затем я попробовал:

->leftJoin('e.delegations', 'd', 'WITH', 'd.name = A') 

Но это возвращение все события

Тогда мне нужно добавить orWhere, чтобы поймать e.delegations = null, но я не знаю, как использовать его, так как это нарушит предыдущий, где это было относительно время. Или, может быть, я могу указать что-то в innerJoin (например, или NULL или что-то в этом роде), но я не нашел его ни в одном Doctrine QueryBuilder Doc Я нашел this на французском, но это только объединение и выбор с помощью Where, то это, безусловно, не оптимальное сравнение с внутренним/левым объединением, и его будет сложнее поддерживать.

+0

Посмотрим, пойду ли я за тобой. Вам нужно какое-либо событие 'e' с делегией 'A' или без какой-либо делегации вообще, но в любом случае с' e.startTime>: date 'где ': date' теперь. –

+1

Вы уже писали инструкцию в SQL? Это поможет вам перевести его в DQL или QueryBuilder. Если нет, вы можете показать структуру своих сущностей/таблиц? – Kwido

+0

@ ViníciusFagundes Вот именно это. И я не знаю, как я могу это сделать с помощью QueryBuilder @Kwido Я did'n попробовать записать его в SQL, но это могло бы, конечно, выглядит следующим образом: 'ВЫБРАТЬ e0_.id AS ID_0, ОТ событий e0_ РЕГИСТРИРУЙТЕСЬ events_delegations e3_ РЕГИСТРИРУЙТЕСЬ делегации d2_ ГДЕ e0_.start_time> NOW() AND ((e0_.id = e3_.events_id И d2_.id = e3_.delegations_id И (d2_.name = A)) ИЛИ e0_.id NOT IN (e3_.events_id)) Здесь я присоединяюсь к WHERE и использую NOT IN для получения события, которое не связано с каким-либо делегированием – homer

ответ

1

Проблема

Эта проблема маленькая хитрость, потому что когда мы фильтруем делегации по имени (d.name = A), для всех целей любое событие (e), которые не имеют этой делегации, но есть и другие, будут так как это не было. Поскольку фильтр «удалит» другие делегации, которые будут возвращены.

Решение

Решите это с помощью подзапроса:

//subquery - only returns event which has delegation 'A' 
$sqb->select('e1.id') 
    ->from('MyNamespace\Entity\Event','e1') 
    ->innerJoin('e1.delegations', 'd', 'WITH', "d.name = 'A'"); 

//main query 
$qb 
    ->leftJoin('e.delegations', 'd')  
    ->andWhere('e.delegation is null or e.id in ('.$sqb->getDQL().')'); 

PS
Если вам нужно использовать placehold (:param) в подзапрос, всегда устанавливайте параметр в основном QueryBuilder.

+1

Большое спасибо, мне просто нужно было измените: '= null' на' IS NULL'. И поскольку параметр «A» является параметром, его необходимо установить в основном запросе, а не в subQuery (если нет, я получаю ошибку: «Слишком мало параметров»). Надеюсь, это поможет другим людям. – homer

+0

Несомненно. Я обновлю ответ. Используйте 'setParameter()' всегда в основном запросе. –

Смежные вопросы