Формат объединения SQL - вложенные внутренние объединения - PullRequest
22 голосов
/ 24 февраля 2011

У меня есть следующая инструкция SQL в устаревшей системе, которую я рефакторинг.Это сокращенное представление для целей этого вопроса, просто пока возвращает count (*).

SELECT COUNT(*)
FROM Table1 
    INNER JOIN Table2 
        INNER JOIN Table3 ON Table2.Key = Table3.Key AND Table2.Key2 = Table3.Key2 
    ON Table1.DifferentKey = Table3.DifferentKey

Это генерирует очень большое количество записей и убивает систему, но может кто-то пожалуйстаобъяснить синтаксис?И может ли это быть выражено как-то иначе?

  • Table1 содержит 419 строк
  • Table2 содержит 3374 строки
  • Table3 содержит 28182 строки

РЕДАКТИРОВАТЬ:

Рекомендуется переформатировать

SELECT COUNT(*)
FROM Table1 
    INNER JOIN Table3
          ON Table1.DifferentKey = Table3.DifferentKey
    INNER JOIN Table2 
          ON Table2.Key = Table3.Key AND Table2.Key2 = Table3.Key2

Ответы [ 2 ]

19 голосов
/ 24 февраля 2011

Для удобства чтения я реструктурировал запрос ... начиная с очевидного самого верхнего уровня - Table1, который затем связывается с Table3, а затем table3 связывается с table2.Намного легче следовать, если вы следуете цепочке отношений.

Теперь, чтобы ответить на ваш вопрос.Вы получаете большое количество в результате декартового произведения.Для каждой записи в Таблице 1, которая соответствует Таблице3, у вас будет X * Y. Тогда для каждого совпадения между таблицей 3 и Таблицей 2 будет одинаковое влияние ... Y * Z ... Таким образом, ваш результат только для одного возможного идентификатора в таблице 1может иметь X * Y * Z записей.

Это основано на незнании того, как нормализация или содержание для ваших таблиц ... если ключ является ПЕРВИЧНЫМ ключом или нет ..

Ex:
Table 1       
DiffKey    Other Val
1          X
1          Y
1          Z

Table 3
DiffKey   Key    Key2  Tbl3 Other
1         2      6     V
1         2      6     X
1         2      6     Y
1         2      6     Z

Table 2
Key    Key2   Other Val
2      6      a
2      6      b
2      6      c
2      6      d
2      6      e

Итак, таблица 1 присоединяется кТаблица 3 приведет (в этом сценарии) к 12 записям (каждая в 1 соединена с каждой в 3).Затем, все это снова, каждый раз соответствующая запись в таблице 2 (5 записей) ... итого 60 (3 tbl1 * 4 tbl3 * 5 tbl2) будет возвращено.

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

SELECT
      COUNT(*)
   FROM
      Table1 
         INNER JOIN Table3
            ON Table1.DifferentKey = Table3.DifferentKey
            INNER JOIN Table2
               ON Table3.Key =Table2.Key
               AND Table3.Key2 = Table2.Key2 
14 голосов
/ 24 февраля 2011

Поскольку вы уже получили помощь по запросу, я постараюсь подсказать вопрос о синтаксисе:

В первом запросе используется менее известный синтаксис ANSI SQL, который позволяет вкладывать объединения между предложениями join и on. Это позволяет вам расширять / связывать ваши объединения и, вероятно, открывает множество других злых, загадочных вещей.

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

select
 count(*)
from Table1 as t1
join Table2 as t2
    join Table3 as t3
    on t2.Key = t3.Key                   -- join #1
    and t2.Key2 = t3.Key2 
on t1.DifferentKey = t3.DifferentKey     -- join #2  

Это выглядит немного странно, потому что соединение # 2 соединяет t1 с t2 без конкретной ссылки на t2 ... однако, оно косвенно ссылается на t2 через t3 - так как t3 соединяется с t2 в соединении # 1. Хотя это может сработать, вы можете найти следующее более (визуально) линейным и привлекательным:

select
 count(*)
from Table1 as t1
    join Table3 as t3
        join Table2 as t2
        on t2.Key = t3.Key                   -- join #1
        and t2.Key2 = t3.Key2   
    on t1.DifferentKey = t3.DifferentKey     -- join #2

Лично я обнаружил, что вложенность таким образом поддерживает мои утверждения в порядке, обрисовывая в общих чертах каждый уровень иерархии отношений. В качестве примечания вам не нужно указывать inner . join является неявно внутренним , если явно не указано иное.

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