2010-10-06 127 views
0

===問題===SQL LEFT JOIN奇怪的語法錯誤?

我在3個表上使用了LEFT JOIN,SQL表達式。當我嘗試運行MS ACCESS 2007時,出現意外錯誤「JOIN表達式不受支持」。

===細節===

這些表都連接

  • 父:是在最高水平
  • child1:父母的孩子
  • 的child2:父
  • 的孩子
  • 孫子1:小孩1

這是SQL表達式導致錯誤:

SELECT * 
FROM ((grandchild1 AS gc 
     LEFT JOIN child1 AS c1 ON gc.child1_id=c1.id) 
     LEFT JOIN parent AS p ON c1.parent_id=p.id) 
     LEFT JOIN child2 AS c2 ON (p.id=c2.parent_id 
           AND c2.start<=gc.time AND gc.time<=c2.stop) 

奇怪的是,下面的表達式中,我只在更換了布爾表達式的一個與真「ON」條款並得到接受:

SELECT * 
FROM ((grandchild1 AS gc 
     LEFT JOIN child1 AS c1 ON gc.child1_id=c1.id) 
     LEFT JOIN parent AS p ON c1.parent_id=p.id) 
     LEFT JOIN child2 AS c2 ON (TRUE 
           AND c2.start<=gc.time AND gc.time<=c2.stop) 

===問題===

  • 是有什麼毛病 語法我的表達?
  • 我注意到的另一件事是我不能在ON子句中使用EXISTS子句 ,這是正常的嗎?

===解決方案===(感謝大衛-W-芬頓)

SELECT * 
FROM ((grandchild1 AS gc 
     INNER JOIN child1 AS c1 ON gc.child1_id=c1.id) 
     INNER JOIN parent AS p ON c1.parent_id=p.id) 
     INNER JOIN child2 AS c2 ON (p.id=c2.parent_id) 
           AND (c2.start<=gc.time) AND (gc.time<=c2.stop) 

回答

1

在你不相等的,則必須有相同的順序表。取而代之的是:

c2.start<=gc.time AND gc.time<=c2.stop 

...你需要這樣的:

c2.start<=gc.time AND c2.stop>=gc.time 

...或:

gc.time>=c2.start AND gc.time<=c2.stop 

您也可以通過測試來看看BETWEEN作品:

gc.time BETWEEN c2.start AND c2.stop 

之間包容性的兩邊,所以我認爲這是完全等同於原來的標準。

所有這一切說,我認爲問題是你正在定義一個連接有三個條件,其中一個適用於一對錶,其他兩個適用於一對不同的表。你的第一個條件,p.id = c2.parent_id,將c2連接到p,而你的第二對非equi條件連接c2和gc。這些連接是棘手的。

我建議使用Access QBE來定義您的連接爲等連接,然後調整連接的SQL以使其成爲非等連接。

或者,在WHERE子句中應用日期/時間標準可能會更簡單,即作爲隱式聯接。

+0

謝謝大衛。正如你所說的,使用QBE讓訪問構建連接就能提供解決方案。我試着用左連接替換它使用的INNER JOIN,但是導致錯誤返回。它也似乎不喜歡我把括號之間的ON子句(我認爲我實際上在幫助它),但它似乎沒有在ON子句中的表的順序問題。我想它使用INNER JOINs更有意義,所以我會堅持。我很高興它解決了。它真的讓我瘋狂 – symbiont 2010-10-07 04:11:41

+0

利用QBE。它確實可以讓你的生活更容易獲得Jet/ACE的正確語法。 – 2010-10-08 01:52:51

1

通常你寫一個參加這樣的:(注意缺少的括號)

SELECT * FROM grandchild1 AS gc 
LEFT JOIN child1 AS c1 ON gc.child1_id=c1.id 
LEFT JOIN parent AS p ON c1.parent_id=p.id 
LEFT JOIN child2 AS c2 ON (p.id=c2.parent_id AND c2.start<=gc.time AND gc.time<=c2.stop) 

關於EXISTS,也許這是一個訪問限制?在ON子句中有一個EXISTS,MySQL非常滿意。

+0

訪問/ Jet/ACE需要parens。 Access QBE將把它們放在需要的地方。將它們排除在外,它會發出抱怨,或者你可能得不到預期的結果。 – 2010-10-06 20:46:24

+0

謝謝,但是,是的,我沒有在其他表達式的每個JOIN周圍的括號,但Access似乎並不接受它...我想這是爲您訪問 – symbiont 2010-10-07 04:14:47

0

看看在reference documentation

它看起來有點特殊,具有隻允許在ON子句中單個操作。 此外,它看起來像訪問2007年,你將不得不嵌套你的聯接。
此外,我認爲日期範圍應該在WHERE子句中。

試試這個:

SELECT * 
FROM grandchild1 AS gc 
LEFT JOIN (

    child1 as C1 LEFT JOIN (

     parent as P LEFT JOIN child2 as C2 ON P.id = C2.parent_id 

) ON c1.parent_id = P.id 

) ON gc.child1_id = C1.id 

WHERE 
    c2.start <= gc.time AND gc.time <= c2.stop 
+0

感謝您的建議。我會用這個,但是我加入的表格是在FROM子句中創建多個表格的一個,所以我真的不能使用WHERE子句(對不起,我的例子沒有給出這些,因爲我試圖保持簡單) – symbiont 2010-10-07 04:18:48

+0

不可能是不正確的。我想這會很不方便 – symbiont 2010-10-07 04:25:04

0

使用WHERE條件並保留ON條件以實現它們的預期目的,即指定如何連接表格而不用於過濾數據。你的方法也很難閱讀,並且不會總是起作用,例如將方法3的WHERE條件移動到ON子句中並親自查看。

drop table if exists t1; 
create table t1(id int unsigned not null primary key); 

drop table if exists t2; 
create table t2(id int unsigned not null primary key); 

insert into t1 (id) values (1),(2),(3),(5),(4),(6); 
insert into t2 (id) values (2),(4),(6); 

-- method 1: 
select t1.id from t1 where id not in (select id from t2); 

-- method 2: 
select t1.id from t1 where not exists (select id from t2 where t1.id = t2.id); 

-- method 3: 
select 
t1.id 
from 
t1 
left outer join t2 on t1.id = t2.id 
where 
t2.id is null; 
+0

雖然大多數顯式連接可以轉換爲等價的WHERE子句(隱式連接),並且大多數數據庫引擎將優化等效語句完全相同,但我不會依賴它。我想查詢查詢優化確定(Google Jet SHOWPLAN瞭解如何)。 – 2010-10-08 01:54:21

+0

對不起,你失去了我 – 2010-10-08 02:43:06