2011-05-18 76 views
1

我有具有UNITTYPE和組織一股股JPA選擇。我有一個包含UnitType和一個組織的合同。我想選擇單位,以及在其集合中具有單位UnitType的合約,或者如果沒有匹配,則具有空UnitType集合的UnitType。基於集合元素匹配,或空集

爲了澄清,在任何情況下我想選擇的單位。如果在合同的UnitType集合中存在具有單位指定類型的合同,那麼我希望選擇該合同。如果這樣的合同不存在,那麼我想選擇根本沒有UnitType的合同。換句話說,我希望適用於本單位類型的合約,但是如果它不存在,我將把單位類型不明的合約作爲默認值。

實施例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鏈接2.0.1對postgres 9.我也得到了與eclipselink 2.2.0相同的結果。

+0

你可以嘗試解釋一些例子嗎?我無法弄清楚你要在這兩個例子的每一個上搜索什麼,但你想要的結果是清楚的。 – Augusto 2011-05-18 19:40:01

+0

補充說明。請讓我知道你是否需要更多。 – digitaljoel 2011-05-18 19:45:16

+0

是你的模型是這樣的: 單位有\ @ManyToOne unitType和\ @ManyToOne組織;合同有\ @ManyToOne組織和\ @OneToMany unitType(或\ @ManyToMany?)。 我理解正確嗎? – wrschneider 2011-11-27 01:36:04

回答

1

您的主要問題是「從單位u,合同c ...其中c.organization.key = u.organization.key」是單位與合同之間的內部連接。根據定義,如果沒有匹配的合同,這將永遠不會返回結果。在「或c.unitTypes爲空」之前,行會從結果集中刪除,一半的條件甚至有機會觸發。

還有第二個更微妙的問題是,如果你可能有一個以上的合同引用相同的單位類型,你可以得到重複的單位回到你的查詢。但是,這種連接可能無法避免,因爲您試圖獲得合同和單位,而不僅僅是單位。 (否則你可以使用存在/不存在,而不是連接。)

現在,這聽起來像你真的不能做你想做的邏輯與單個連接。像「如果它存在,拿別的東西,否則採取其他的,但不是兩個」條件邏輯將需要多個連接,然後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,我很傷心地說有沒有什麼好辦法讓你在一個單一的查詢想要的東西。

+0

明天晚上我會玩這個解決方案。謝謝你的回答,我會告訴你它是怎麼回事。 – digitaljoel 2011-11-28 01:47:28

+0

這個問題有聚結類似的查詢結構/左連接來實現默認邏輯:http://stackoverflow.com/questions/8290033/operations-within-group-when-group-by – wrschneider 2011-11-28 14:35:52

+0

關於你指出的第一個問題你的回答:合同組織和單位組織的內在聯繫是有意的。總會有一個具有匹配組織的合同,所以我們肯定應該到達檢查單位類型和合同類型的部分。雖然你的答案的第二部分是非常有幫助的。我會再給它幾天的時間,看看有沒有人加入。謝謝你花時間回答。 – digitaljoel 2011-11-29 02:24:33