Left Join фильтрует строки, которые я ожидаю показать при использовании HQL - PullRequest
0 голосов
/ 19 ноября 2010

У меня есть что-то похожее на следующий HQL:

select count(distinct car.id), 
count(distinct w1.id), 
count(distinct w2.id), 
count(distinct w3.id)
from Car car
left join Wheel w1
left join Wheel w2 with w2.IsFrontWheel == true
left join Wheel w3 with w3.IsFrontWheel == false
where w1.ManufacturedDate > :manufacturedDate
and w2.ManufacturedDate > :manufacturedDate
and w3.ManufacturedDate > :manufacturedDate
group by car.Make

Этот HQL динамически генерируется по выбору моего пользователя, когда он запускает отчет. Здесь важно отметить, что пользователь динамически выбирает фильтр, что заставляет этот HQL динамически создавать предложение where.

У меня правильно генерируется предложение where.

Моя проблема заключается в том, что, если вы выполните результирующий запрос в SQL Server 2008, конечный результат состоит в том, что, если есть Колеса (w1 или w2 или w3), у которых любой ManufacturedDate больше чем При заданном параметре в отчете полностью пропускается этой записи.

Я обнаружил причину этого, в этой статье здесь .

Моя проблема в том, что я не могу добавить эти фильтры в предложение with в HQL. В приведенном выше примере я мог бы добавить ограничение к предложению with, но созданный мной механизм отчетов позволяет пользователю выполнять гораздо более сложную фильтрацию, чем эта, большинство из которых не допускаются в предложении with. Я когда-либо пытался поместить некоторые из сгенерированных HQL в with и убедился, что это действительно так, и большинство из них не будут выполняться, потому что они требуют дополнительных ограничений на другие таблицы.

Итак, мой вопрос:

Есть ли способ изменить этот HQL, чтобы вернуть недостающие записи? В статье, которую я перечислил выше, кто-то упомянул, что если вы принимаете во внимание NULL, вы можете получить записи обратно, но я не знаю, каким образом он имел в виду, и если это возможно, я определенно хотел бы знать как.

UPDATE

Я вынужден поместить динамический фильтр в предложение where, потому что пользователь также может сделать что-то вроде этого:

select count(distinct car.id), 
count(distinct w1.id), 
count(distinct w2.id), 
count(distinct w3.id)
from Car car
left join Wheel w1
left join Wheel w2 with w2.IsFrontWheel == true
left join Wheel w3 with w3.IsFrontWheel == false
where w1.Buyer.FirstName = :firstName
and w2.Buyer.FirstName = :firstName
and w3.Buyer.FirstName = :firstName
group by car.Make

, который, если я переписал в предложении с

select count(distinct car.id), 
count(distinct w1.id), 
count(distinct w2.id), 
count(distinct w3.id)
from Car car
left join Wheel w1 with w1.Buyer.FirstName = :firstName
left join Wheel w2 with w2.IsFrontWheel == true 
    and w2.Buyer.FirstName = :firstName
left join Wheel w3 with w3.IsFrontWheel == false 
    and w3.Buyer.FirstName = :firstName
group by car.Make

не запускается, NHibernate выдает исключение.

Ответы [ 4 ]

2 голосов
/ 19 ноября 2010

Ваша проблема заключается в фильтрации левосторонних столбцов в предложении WHERE:

select count(distinct car.id), 
count(distinct w1.id), 
count(distinct w2.id), 
count(distinct w3.id)
from Car car
left join Wheel w1
left join Wheel w2 with w2.IsFrontWheel == true
left join Wheel w3 with w3.IsFrontWheel == false
where w1.ManufacturedDate > :manufacturedDate --<<<<
and w2.ManufacturedDate > :manufacturedDate   --<<<<
and w3.ManufacturedDate > :manufacturedDate   --<<<<
group by car.Make

попробуйте это:

select count(distinct car.id), 
count(distinct w1.id), 
count(distinct w2.id), 
count(distinct w3.id)
from Car car
left join Wheel w1 with w1.ManufacturedDate > :manufacturedDate
left join Wheel w2 with w2.IsFrontWheel == true AND w2.ManufacturedDate > :manufacturedDate
left join Wheel w3 with w3.IsFrontWheel == false AND w3.ManufacturedDate > :manufacturedDate
group by car.Make

когда вы сравниваете w2.ManufacturedDate > :manufacturedDate, это похоже на выполнение null > :manufacturedDate, в результате которого получается NULL, а строка выбрасывается, как будто это внутреннее соединение. перемещение условия в положение LEFT JOIN предотвращает это.

EDIT
попробуйте это:

select count(distinct car.id), 
count(distinct w1.id), 
count(distinct w2.id), 
count(distinct w3.id)
from Car car
left join Wheel w1
left join Wheel w2 with w2.IsFrontWheel == true
left join Wheel w3 with w3.IsFrontWheel == false
where ISNULL(w1.ManufacturedDate,'99991231') > :manufacturedDate
and ISNULL(w2.ManufacturedDate,'99991231)' > :manufacturedDate
and ISNULL(w3.ManufacturedDate,'99991231') > :manufacturedDate
group by car.Make
0 голосов
/ 19 ноября 2010

Попробуйте следующее:

left join Wheel w1
left join w1.Buyer b1 with b1.FirstName = :firstName

То же самое для всех остальных.Это должно сделать.

0 голосов
/ 19 ноября 2010

Я собираюсь погрузиться, хотя я ничего не знаю о HQL:)

Если вам нужно избегать использования WITH, тогда вам нужно, чтобы предложение WHERE было истинным, когда вы хотитесчитать в результате случается.Это условие не совсем понятно из вашего вопроса, но что-то вроде:

where ISNULL(w1.ManufacturedDate, *some_future_value*) > :manufacturedDate

... где * some_future_value * - это значение, которое вы каким-то образом генерируете, чтобы быть дальше в будущее, чем параметр madeDate.Так что, возможно, ваше максимально возможное значение даты, или ": madeDate + 1 ', или все, что вам подходит.

0 голосов
/ 19 ноября 2010

Проверьте ключевое слово «with» в HQL нажмите

...