2010-09-23 4 views
16

У меня есть три таблицы: R, S и P.SQL, соединяющий три таблицы, приоритет соединения

Таблица R Соединения с S через внешний ключ; там должно быть по крайней мере одна запись в S, так что я могу JOIN:

SELECT 
     * 
    FROM 
     R 
    JOIN S ON (S.id = R.fks) 

Если нет записи в S, то я не получаю никаких строк, это нормально.

Тогда таблица S соединяется с P, где записи Р может или не может присутствовать и вместе с С.

Так что я

SELECT 
     * 
    FROM 
     R 
    JOIN S ON (S.id = R.fks) 
    LEFT JOIN P ON (P.id = S.fkp) 

Что делать, если я хотел второй РЕГИСТРИРУЙТЕСЬ быть связаны в S не R, как если бы я мог использовать круглые скобки:

SELECT 
     * 
    FROM 
     R 
    JOIN (S ON (S.id = R.fks) JOIN P ON (P.id = S.fkp)) 

Или это уже естественное поведение декартова продукта между R, S и P?

+0

Вы можете уточнить эту часть «Что, если бы я хотел, чтобы второй РЕГИСТРИРУЙТЕСЬ быть привязанным к S не R» Сейчас таблицы соединяются, как R объединения с S, а затем покинул присоединиться к P. –

+0

Пытаюсь чтобы понять, есть ли способ, которым я могу отдать предпочтение объединению, например, если они были арифметическими операторами. Я не понимаю, если это неявно в условии соединения или нет. – vulkanino

+0

Дайте нам пример данных о том, чего вы надеетесь достичь, это отличается от обычного соединения, и мы можем лучше показать вам, что делать. Возможно, производная таблица может делать то, что вы хотите, но я не уверен точно, что вы хотите. – HLGEM

ответ

26

Все виды внешних и нормальных объединений находятся в одном классе приоритетов, а операторы действуют слева направо на заданном уровне вложенности запроса. Вы можете поместить выражение объединения с правой стороны в круглые скобки, чтобы заставить его вступить в силу сначала; просто помните, что вам нужно переместить предложение ON соединения, которое теперь находится за пределами соединения, в которое вы помещаете parens.

(PostgreSQL пример)

В SELECT * FROM a LEFT JOIN b ON (a.id = b.id) JOIN c ON (b.ref = c.id);

СПР присоединиться вступает в силу первый, но мы можем заставить бв присоединиться вступили в силу первых, выполнив:

SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);

Часто вам может выражать одно и то же без дополнительных скобок, перемещая соединения и изменяя направление внешнего соединения, например

SELECT * FROM b JOIN c ON (b.ref = c.id) RIGHT JOIN a ON (a.id = b.id);

+1

Прояснение: все операторы объединения имеют одинаковый приоритет, и все они имеют ассоциацию слева направо. Это способ вычитания (-) и деления (/) работают практически во всех языках программирования. Изменение порядка операндов не влияет на его «приоритет» (аспект грамматики SQL, а не операнд в любом случае). Это позволяет использовать ассоциативность слева-направо объединения для достижения желаемой семантики составных объединений. Но это не меняет ни приоритета, ни ассоциативности ничего в выражении - только его контекст интерпретации. –

+0

Достаточно честный. Что второе слово, которое передает эффект одного оператора, предшествующего эффекту другого оператора, но не приоритет, потому что это уже принято? – rakslice

+0

Перефразированный. Кроме того, насколько мне не нравится наступать на чье-то жаргонное слово, используя его для определения словаря (нет, я этого не делаю), то, что действительно измельчает мои передачи, - это нечто вроде «ассоциативности», где слово жаргона - это математическая терминология, которая была присвоена вычислительным миром. – rakslice

1

Второй присоединиться является привязан к S, как вы в явной форме состояния JOIN P ON (P.id = S.fkp) - не столбец из R не упоминается в соединении.

+0

ОК, но нет способа, в общем, дать преимущество присоединению? – vulkanino

+0

Я не думаю, что SQL работает так, как вы думаете. Ответ Пауля Спангла описывает, как SQL «думает» о присоединениях. –

2

При вступлении в третью таблицу, ваш первый запрос

SELECT 
     * 
    FROM 
     R 
    JOIN S ON (S.id = R.fks) 

походит на производную таблицу, в которой вы присоединяетесь третью таблицу. Поэтому, если не создает строк, то объединение P никогда не даст никаких строк (потому что вы пытаетесь присоединиться к пустой таблице).

Итак, если вы ищете правила приоритета, тогда в этом случае он устанавливается только с помощью LEFT JOIN, а не JOIN.

Однако, возможно, я не понимаю ваш вопрос, потому что, если бы я писал запрос, я бы поменял S и R. например.

SELECT 
     * 
    FROM 
     S 
    JOIN R ON (S.id = R.fks) 
+0

Учтите, что мне нужно объединить 3 таблицы, а не 2. – vulkanino

+1

Это просто работает слева направо. Единственный способ, о котором я могу думать, - положить целую производную таблицу в некоторые скобки. –

1

Нет совпадений для присоединения, это ассоциативная операция. Старый синтаксис, разделенный запятой, сделал это ясным, новый (который предположительно приготовлен для имитации реляционной алгебры) запутан. Внешние соединения (используемые отдельно или вместе с регулярными объединениями), однако, не являются ассоциативными.

+3

Учитывая, что ОП спрашивает о LEFT JOINS, утверждение, что JOINS является ассоциативным, является обманчивым. – Taemyr

0
with a as (select 1 as test union select 2) 
select * from a left join 
a as b on a.test=b.test and b.test=1 inner join 
a as c on b.test=c.test 
go 
with a as (select 1 as test union select 2) 
select * from a inner join 
a as b on a.test=b.test right join 
a as c on b.test=c.test and b.test=1 

В идеале мы хотели бы надеяться, что вышеупомянутые два запроса одинаковы. Тем не менее, это не так, поэтому любой, кто говорит, что правое соединение может быть заменено левым соединением во всех случаях, неверно. Только используя правильное соединение, мы получим требуемый результат.

+1

правые соединения не имеют ничего общего с этим вопросом, и никто не говорит, что они одинаковы. – Hogan

Смежные вопросы