SQL LEFT JOIN странная синтаксическая ошибка? - PullRequest
0 голосов
/ 06 октября 2010

=== проблема ===

Я использую LEFT JOIN, выражение SQL, для 3 таблиц. я получаю неожиданную ошибку «JOIN выражение не поддерживается» из MS ACCESS 2007, когда я пытаюсь запустить его.

=== подробности ===

все эти таблицы связаны

  • родитель: находится на самом высоком уровне
  • 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)

странно, следующее выражение, в котором я заменил только одно из логических выражений на TRUE в предложении «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)

=== вопросы ===

  • что-то не так с синтаксис моего выражения?
  • я заметил еще одну вещь: я не могу использовать предложение EXISTS внутри предложения ON, это нормально?

=== Решение === (спасибо Дэвид-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)

Ответы [ 4 ]

1 голос
/ 07 октября 2010

В вашем не равном объединении таблицы должны быть в том же порядке.Вместо этого:

  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

Вы также можете проверить, еслиМЕЖДУ работает:

  gc.time BETWEEN c2.start AND c2.stop

МЕЖДУ включительно с обеих сторон, поэтому я думаю, что это в точности соответствует вашим исходным критериям.объединение с тремя условиями, одно из которых применяется к одной паре таблиц, а два других - к другой паре таблиц.Ваше первое условие, p.id = c2.parent_id, соединяет c2 с p, а ваша вторая пара неэквивалентных условий соединяет c2 и gc.Подобные объединения довольно сложны.

Я бы предложил использовать Access QBE для определения ваших объединений как равных объединений, а затем настроить SQL для объединения, чтобы сделать его не равным объединению.

В качестве альтернативы может быть проще применить критерии даты / времени в предложении WHERE, т. Е. Как неявное соединение.

1 голос
/ 06 октября 2010

Обычно вы пишете объединение так:

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, возможно, это ограничение доступа? MySQL вполне доволен наличием EXISTS в предложении ON.

0 голосов
/ 08 октября 2010

используйте условие WHERE и оставьте условия ON для цели, для которой они предназначены, а именно, для указания того, как таблицы должны объединяться, а не для фильтрации данных.Ваш метод также намного сложнее для чтения и не всегда работает, например, переместите условие WHERE метода 3 в предложение 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 голосов
/ 06 октября 2010

Ознакомьтесь с справочной документацией

Похоже, что в предложении 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...