我有一个Unit,它有一个UnitType和一个Organization。我有一个合同,其中包含UnitTypes和Organization的集合。我想选择单位,以及在其集合中具有Unit的UnitType的合同,或者如果没有匹配则选择具有空UnitType集合的UnitType。
为了澄清,在每种情况下我都想选择单位。如果在合约的UnitTypes集合中存在具有单位指定类型的合约,那么我想选择该合约。如果这样的合同不存在,那么我想选择根本没有UnitTypes的合同。换句话说,我希望合同适用于此单位的类型,但如果它不存在,我将采用单位类型不可知的合同作为默认值。
示例1:
Unit A has type XYZ.
Contract B has types [ ABC, DEF ]
Contract C has types []
在这种情况下,我会选择单位和合同C,因为B在类型上没有匹配。
示例2:
Unit A has type XYZ
Contract B has types [XYZ, ABC]
Contract C has types []
在这种情况下,我会选择合约B,因为它与单位的类型相匹配。
以下查询适用于示例2,但不适用于示例1。
SELECT NEW mypackage.view.MyAggregateView(
u
, MAX(sc.serviceDate)
, c.survey.key )
FROM Contract c
, Unit u
LEFT JOIN u.serviceCalls sc
WHERE c.organization.key = u.organization.key
AND u.organization.key = :organizationKey
AND ((u.unitType MEMBER OF c.unitTypes)
OR (c.unitTypes IS EMPTY))
GROUP BY u, c.survey.key
如何在这两种情况下完成这项工作并确保获得正确的合同?
又一个例子:
我最近再遇到这个问题。我有一个区域,其中包含一系列邮政编码和可选的组织集合。我还有一个单位,它有一个1-1到一个组织,并有一个邮政编码。我想获得该地区邮政编码中的所有相应单位。如果该地区没有组织,那么我应该获得邮政编码中的所有单位,否则我应该只获得组织与该地区内指定的组织之一相匹配的单位。
这是我的查询
Select u.key, u.organization.key
from Unit u, Region r
where r.key = -1
and u.address.postalCode member of r.zips
and r.organizations is empty
此查询可以获得我所有预期的结果。以下查询不应该限制结果集,因为它只添加了一个OR,但没有给出任何结果。
Select u.key, u.organization.key
from Unit u, Region r
where r.key = -1
and u.address.postalCode member of r.zips
and ((r.organizations is empty) OR (r.organizations is not empty and u.organization member of r.organizations))
我正在使用eclipse link 2.0.1对抗postgres 9.我也使用eclipselink 2.2.0得到了相同的结果。
答案 0 :(得分:1)
您的主要问题是“来自Unit u,Contract c ...其中c.organization.key = u.organization.key”是Unit和Contract之间的内部联接。根据定义,如果没有匹配的合同,这将永远不会返回结果。在“或c.unitTypes为空”之前,行从结果集中删除了一半的条件甚至有机会触发。
还有一个更微妙的问题是,如果您可能有多个引用相同单元类型的合同,则可以在查询中返回重复单元。但是,这种联合可能是不可避免的,因为你试图获得合同和单位,而不仅仅是单位。 (否则你可以使用exists / not exists而不是join。)
现在,听起来你真的不能用一个连接来做你想要的逻辑。有条件的逻辑,比如“拿东西,如果它存在,别拿东西,但不是两个”需要多个连接,然后是case / when逻辑选择使用哪个。
此时我想知道你是否会因为两个单独的查询而变得更好。根据常见情况和应用程序的整体架构,您的性能甚至可能更好地运行两个简单的查询并进行两次往返,而不是进行复杂的查询以避免往返。即使你的性能受到轻微打击,我也几乎更喜欢它的可读性和可维护性。
也就是说,如果我必须在SQL中执行此操作,并且它绝对必须在单个查询中,那么它将是可行的但完全不是:
select u.*, c.* from (
select unit_id,
coalesce(matching.contract_id, non_matching.contract_id)
as contract_id
from Unit u
**left** join Contract matching on ([match on unit type])
left join Contract non_matching on ([unit types empty])
) subquery join Unit u on subquery.unit_id = u.unit_id
join Contract c on subquery.contract_id = c.contract_id
或者将两个查询与UNION ALL组合在一起,并在返回第一个结果后停止。
然而,这两个选项都没有转换为JPA / JPQL。 JPQL没有UNION运算符,并且JPQL不支持任意条件的外连接,仅在导航关系时支持“left join u.serviceCalls”。我不认为你可以将笛卡尔“从契约c,单位u”变成外连接。
因此,对于JPQL,我很伤心地说有没有什么好办法让你在一个单一的查询想要的东西。