SQL LEFT JOIN奇怪的语法错误?

时间:2010-10-06 18:39:38

标签: sql syntax join ms-access-2007

===问题===

我在3个表上使用LEFT JOIN,SQL表达式。当我尝试运行它时,我从MS ACCESS 2007收到意外错误“不支持JOIN表达式”。

===细节===

这些表都已连接

  • parent:处于最高级别
  • child1:父母的孩子
  • child2:父母的孩子
  • 孙子1:child1的孩子

这是导致错误的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”子句中只替换了其中一个布尔表达式为TRUE的以下表达式确实被接受了:

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)

===问题===

  • 有什么问题 我的表达式的语法?
  • 我注意到的另一件事是我不能使用EXISTS条款 在ON子句中,这是正常的吗?

=== solution ===(感谢David-W-Fenton)

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)

4 个答案:

答案 0 :(得分: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)

(注意缺少的parens。)

关于EXISTS,也许这是一个Access限制? MySQL很高兴在ON子句中有一个EXISTS。

答案 1 :(得分:1)

在非equi连接中,您必须使用相同的顺序。而不是:

  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

BETWEEN双方都是包容性的,所以我认为它完全等同于你原来的标准。

所有这一切,我认为问题在于您定义了一个具有三个条件的连接,其中一个适用于一对表,另外两个适用于另一对表。你的第一个条件,p.id = c2.parent_id,将c2加到p,而你的第二对非equi条件加入c2和gc。这些类型的连接很棘手。

我建议使用Access QBE将连接定义为equi-joins,然后调整连接的SQL以使其成为非equi连接。

或者,在WHERE子句中应用日期/时间标准可能更简单,即作为隐式连接。

答案 2 :(得分: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

答案 3 :(得分: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;