Внутреннее соединение и внешнее соединение; важен порядок таблиц в? - PullRequest
16 голосов
/ 09 октября 2008

Почему порядок таблиц важен при объединении внешнего и внутреннего соединения? с postgres происходит следующее:

SELECT grp.number AS number,     
       tags.value AS tag   
FROM groups grp,
     insrel archiverel  
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber   
WHERE archiverel.snumber = 11128188 AND    
      archiverel.dnumber = grp.number 

с результатом:

ERROR:  invalid reference to FROM-clause entry for table "grp" LINE 5: LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.d... 
^ HINT:  There is an entry for table "grp", but it cannot be referenced from this part of the query.

когда группы меняются в FROM, все работает:

SELECT  grp.number AS number,     
        tags.value AS tag   
FROM    insrel archiverel,
        groups grp
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber   
WHERE   archiverel.snumber = 11128188 AND    
        archiverel.dnumber = grp.number 

Ответы [ 5 ]

20 голосов
/ 09 октября 2008

Я считаю, что вы можете думать об этом как о проблеме приоритета оператора.

Когда вы пишете это:

FROM groups grp,
     insrel archiverel  
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber   

Я думаю, что он интерпретируется синтаксическим анализатором так:

FROM groups grp,
(
  (
     insrel archiverel  
     LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
  )
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber
)

Если это так, то в самом внутреннем соединении «grp» не связан.

Когда вы переворачиваете строки с помощью «groups» и «insrel», самое внутреннее соединение применяется к «groups» и «ownrel», поэтому оно работает.

Возможно, это также сработает:

    FROM groups grp
         JOIN insrel archiverel  ON archiverel.dnumber = grp.number
    LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
    LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188
18 голосов
/ 09 октября 2008

Я не думаю, что кто-то это достаточно прибил или объяснил очень хорошо. Вы объединяете объединения «старый стиль» (тета) и «новый стиль» (ANSI), которые, как я сильно подозреваю, группируются так, как вы этого не ожидаете. Посмотрите на это так:

SELECT * FROM a, b JOIN c ON a.x = c.x

все равно что сказать

SELECT * FROM a, (b JOIN c on a.x = c.x)

где заключенная в скобки вещь представляет собой набор таблиц, объединенных в одну виртуальную таблицу, для объединения с тета-соединением против 'a'. Очевидно, что таблица «a» не может быть частью объединения, так как она присоединяется только позже. Обратитесь, и вы делаете

SELECT * FROM b, (a JOIN c on a.x = c.x)

, что совершенно понятно и так хорошо. Я не уверен, почему вы не используете синтаксис ANSI объединения для всего этого, хотя, кажется немного странным (и жестоким для человека, который должен его поддерживать!)

5 голосов
/ 09 октября 2008

Поскольку в первом из них группа grp не является частью объединения, к которому относится предложение ON.

4 голосов
/ 09 октября 2008

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

SELECT grp.number AS number,     
       tags.value AS tag   
FROM groups grp
JOIN insrel archiverel ON archiverel.dnumber = grp.number
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber   
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber   
WHERE archiverel.snumber = 11128188

Мне было бы интересно узнать больше, если поведение является намеренным.

2 голосов
/ 09 октября 2008

Для внутреннего объединения порядок таблиц не важен.

Для внешнего соединения это так. Все строки из таблицы на указанной стороне (это соединение ВЛЕВО или ВПРАВО) будут включены, тогда как из таблицы на другой стороне будут включены только строки, соответствующие критериям соединения. *

Поскольку ВНЕШНИЕ СОЕДИНЕНИЯ держат все строки с одной стороны, говорят, что они (в общем) увеличивают наборы результатов. ВНУТРЕННИЕ СОЕДИНЕНИЯ сохраняют строки с обеих сторон только в том случае, если они совпадают, поэтому, как правило, говорят, чтобы уменьшить наборы результатов. Таким образом, вы обычно хотите выполнить свои ВНУТРЕННИЕ СОЕДИНЕНИЯ до НАРУЖНОГО СОЕДИНЕНИЯ (когда это возможно).

В вашем случае это почти наверняка результат злого синтаксиса A, B.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...