2010-10-06 200 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