2011-01-24 87 views
7

我一直在試圖追查我遇到的查詢問題。查詢實際上是通過HQL從HQL生成的,但生成的SQL並沒有達到我所期望的。稍微修改SQL會產生正確的結果,但我不確定爲什麼修改應該有所作爲。交叉連接行爲(SQLServer 2008)

原始查詢(沒有返回)

select sched.id, max(txn.dttm), acc.id 
from PaymentSchedulePeriod sched 
cross join PaymentSchedulePayment pay 
right outer join AccountTransaction txn on pay.accountTransactionFk=txn.id 
right outer join Account acc on txn.accountFk=acc.id 
where sched.accountFk=acc.id 
group by sched.id, acc.id 

修改後的查詢 - 交叉連接逗號代替(隱式交叉連接)

返回一行

select sched.id, max(txn.dttm), acc.id 
from PaymentSchedulePeriod sched 
,PaymentSchedulePayment pay 
right outer join AccountTransaction txn on pay.accountTransactionFk=txn.id 
right outer join Account acc on txn.accountFk=acc.id 
where sched.accountFk=acc.id 
group by sched.id, acc.id 

我的理解,這可能不正確的是,寫作from Table1 a, Table2 b與寫作from Table 1 a cross join Table2 b相同。所以我不明白爲什麼查詢返回不同的結果。

是否與第一個查詢中導致此問題的交叉連接和外部連接之間的交互有關?我查看了查詢計劃,第二個查詢計劃看起來很合理。第一個沒有外連接,這很奇怪。

這是SQLServer的2008年

回答

9

JOIN具有比逗號更高的優先級,讓你的第二個發言被解釋爲(注意我加了括號):

select sched.id, max(txn.dttm), acc.id 
from PaymentSchedulePeriod sched 
,(PaymentSchedulePayment pay 
right outer join AccountTransaction txn on pay.accountTransactionFk=txn.id 
right outer join Account acc on txn.accountFk=acc.id) 
where sched.accountFk=acc.id 
group by sched.id, acc.id 

另請參見:JOIN precendence rules per SQL-99

+0

謝謝+1。在我的HQL中,我使用了COMMA,所以我不確定爲什麼Hibernate會渲染CROSS JOIN。我切換了from子句,所以Period表是最後一個,它正常工作。仍然產生了交叉連接,但是因爲它的優先級是最後的,所以它按預期工作。 – 2011-01-24 18:01:03

0

不看實際的數據和查詢計劃,我會說(好的,猜測)它與優化器構建查詢計劃的方式有關。

在第一,它是或多或少明確告知「採取的第一個表,交叉與第二個連接,然後右連接中三分,然後在右四結合」

在第二,那交叉加入是(至少對我來說是這樣)暗示。從WHERE子句中執行所有連接的時代開始,這就是「舊」的SQL語法,這也是我的思維方式 - 意味着數據庫引擎可以自行解決執行進程表。換句話說,SQL並沒有給出連接表的特定順序。 (使用內部連接和交叉連接,沒有區別,但使用外部連接可以產生巨大差異。)

...我更喜歡@ Joe的答案(upvoted),因爲它在技術上是準確的。無論如何,我只是爲了細節而拋棄它。