Условие значения FULL OUTER JOIN - PullRequest
3 голосов
/ 18 января 2012

Мне нужно добавить условие значения в ПОЛНОЕ НАРУЖНОЕ СОЕДИНЕНИЕ.

Т.е. мне нужно сделать следующее:

SELECT *
FROM Table1
FULL OUTER JOIN Table2 ON Table1.Field1 = Table2.Field1 AND Table2.Field2 > 5

Но этот скрипт не работает.На самом деле это выглядит так, как будто условие (Table2.Field2> 5) вообще никогда не применялось.

Такая же проблема возникает для RIGHT OUTER JOIN, поэтому я думаю, что причина в том, что когда есть RIGHT или FULL, соединение noзначения условий применяются к правой таблице в соединении.Почему это происходит?Существует ли концептуальное объяснение такого поведения?

И, конечно, главный вопрос - как решить эту проблему.

Есть ли способ решить эту проблему без использования подзапросов?

SELECT *
FROM Table1
FULL OUTER JOIN (SELECT * FROM Table2 WHERE Table2.Field2 > 5) AS t2 ON Table1.Field1 = t2.Field1

Ответы [ 3 ]

3 голосов
/ 18 января 2012

То, что вы хотите, может быть переформулировано как:

 SELECT *
   FROM Table1
   LEFT JOIN Table2 ON Table1.Field1 = Table2.Field1 AND Table2.Field2 > 5
  UNION ALL
 SELECT *
   FROM Table1
  RIGHT JOIN Table2 ON Table1.Field1 = Table2.Field1
  WHERE Table2.Field2 > 5
    AND Table1.Field1 IS NULL

, но использование подзапроса, предложенного вами, является IMO лучшим вариантом.

1 голос
/ 18 января 2012

Довольно сложный, но без подзапросов

SELECT  Table1.*
        , CASE WHEN Table2.Field2 > 5 THEN Table2.Field1 ELSE NULL END
        , CASE WHEN Table2.Field2 > 5 THEN Table2.Field2 ELSE NULL END        
FROM    Table1
        FULL OUTER JOIN Table2 ON Table1.Field1 = Table2.Field1
WHERE   COALESCE(Table2.Field2, 6) > 5
        OR Table1.Field1 = Table2.Field1

Тестовый скрипт

;WITH Table1 AS (
  SELECT * FROM (VALUES
    (1, 1)
    , (2, 2)
    , (5, 5)
    , (6, 6)
  ) AS Table1 (Field1, Field2)
)
, Table2 AS (
  SELECT * FROM (VALUES
    (1, 1)
    , (3, 3)
    , (4, 4)
    , (5, 5)
    , (7, 7)
  ) AS Table2 (Field1, Field2)
)
SELECT  Table1.*
        , CASE WHEN Table2.Field2 > 5 THEN Table2.Field1 ELSE NULL END
        , CASE WHEN Table2.Field2 > 5 THEN Table2.Field2 ELSE NULL END        
FROM    Table1
        FULL OUTER JOIN Table2 ON Table1.Field1 = Table2.Field1
WHERE   COALESCE(Table2.Field2, 6) > 5
        OR Table1.Field1 = Table2.Field1

Результаты

 Field1 Field2 Field1 Field2
 1      1      NULL   NULL
 5      5      NULL   NULL
 NULL   NULL   7      7
 6      6      NULL   NULL
 1      1      NULL   NULL
 2      2      NULL   NULL
0 голосов
/ 30 мая 2016

Раньше это меня смущало.Теперь я понимаю!Условия после «on» (в вашем случае: Table1.Field1 = Table2.Field1 AND Table2.Field2> 5) сообщают оператору соединения, какие строки из двух таблиц объединяются.Это означает, что когда и только строки row1 из таблицы1 и строки2 из таблиц удовлетворяют как row1.field1 = row2.field2, так и row2.field2> 5, строки1 и строка2 объединяются.Остальные строки не объединяются.

Таким образом, при полном внешнем объединении результирующий набор будет затем объединяться в строки, несоединенные строки из таблицы1 и несоединенные строки из таблицы2.При правом объединении результирующий набор будет состоять из строк, не связанных строк из таблицы2.В любом случае строки из таблицы 2 с полем2 <= 5 будут среди результирующих наборов несвязанных строк из таблицы 2. </p>

Вот почему «Table2.Field2> 5» работает правильно в левом соединении, ноне то, чтобы «правильно» в правильном или полном объединении, но условия ценности действительно делают свою работу правильно.

...