Как я могу заменить левое соединение в SQL - PullRequest
6 голосов
/ 22 сентября 2011

Может кто-нибудь сказать мне, как я могу написать эквивалент левого объединения, не используя в действительности левые объединения.

Select * from a left join b on a.name = b.name.

Ответы [ 3 ]

10 голосов
/ 22 сентября 2011

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

Это внешнее соединение:

SELECT DISTINCT T1.id, T1.value, T2.other_value
  FROM T1
       LEFT OUTER JOIN T2
          ON T1.id = T2.id;

… семантически эквивалентен этому коду SQL:

SELECT T1.id, T1.value, T2.other_value
  FROM T1
       INNER JOIN T2
          ON T1.id = T2.id
UNION
SELECT T1.id, T1.value, NULL
  FROM T1
 WHERE NOT EXISTS (
                   SELECT * 
                     FROM T2
                    WHERE T1.id = T2.id
                  );

Второй запрос может показаться сложным, но это только из-за того, как SQL был разработан / развит. Вышесказанное - это просто естественное соединение, союз и полусоединение. Однако в SQL нет оператора semi-join, он требует указывать списки столбцов в предложении SELECT и писать предложения JOIN, если в вашем продукте не реализован синтаксис NATURAL JOIN стандартного SQL, что приводит к большому количеству кода для выражения. что-то довольно простое.

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

1 голос
/ 22 сентября 2011

Хотя левое внешнее объединение является рекомендуемым способом написания sql по сравнению с альтернативным, но все же мы можем достичь левого внешнего объединения, используя объединение для набора результатов.Если у нас есть две таблицы Table1 и Table 2, мы можем достичь этого следующим образом:

select
       A.Id, 
       A.Col1, 
       A.Col2, 
       A.Col3, 
       B.Id Col4, 
       B.Col1 Col5, 
       B.Col2 Col6, 
       B.Col3 Col7, 
       B.Col4 Col8
from   Table1 A, Table2 B
where  A.Id = B.Id

union all

select
       A.Id, 
       A.Col1, 
       A.Col2, 
       A.Col3, 
       null as Col4, 
       null as Col5, 
       null as Col6, 
       null as Col7, 
       null as Col8
from   Table1 A
where  not exists(select 1 from Table2 B where B.Id = A.Id)

Это поможет достичь того же результата, но из-за использования Union могут возникнуть некоторые проблемы с производительностью в случаестолы большие.

0 голосов
/ 22 сентября 2011

Oracle замаскированный левое соединение:

SELECT * FROM A, B
 WHERE a.name = b.name(+)

Общий:

SELECT a.*, case c.existence WHEN 1 then c.name ELSE NULL END
  FROM A
 INNER JOIN ( SELECT name name, 1 existence FROM B
               UNION ALL
              SELECT a.name name, 0 existence FROM A
               WHERE a.name NOT IN ( SELECT name FROM B )
            ) C
    ON c.name = a.name
...