СЛЕДУЮЩЕЕ НАРУЖНОЕ СОЕДИНЕНИЕ с предложением WHERE - PullRequest
21 голосов
/ 23 марта 2010

У меня есть две таблицы. indRailType содержит список имен в сочетании со значением идентификатора, который я использую в других таблицах для указания типа рейки. WO_BreakerRail содержит столбец даты и столбец кода железной дороги, который соответствует тому же коду в indRailType и некоторым другим данным. В WO_BreakerRail есть строка для любого вида деятельности для каждого типа рельсов, для каждой даты. Таким образом, у меня может быть 3 строки, датированные 3/19/2010, каждая строка указывает свой код железной дороги и что произошло.

Когда я использую следующее LEFT OUTER JOIN, я получаю таблицу со всеми типами рельсов с нулями в строках, где 19-го ничего не произошло. Теперь, это работает только потому, что у меня только одна дата, представленная в моей таблице WO_BreakerRail прямо сейчас, 19-го числа. Когда я добавлю больше строк с разными датами, все пойдет не так.

Это мой оператор SQL, который сейчас дает мне именно те результаты, которые я хочу:

SELECT WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, 
    WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, 
    WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop
FROM indRailType
LEFT OUTER JOIN WO_BreakerRail 
    ON indRailType.RailCode = WO_BreakerRail.RailCode

Теперь, когда я добавляю предложение WHERE WO_BreakerRail.Date = @Date, я теряю все строки в JOIN, с которыми ничего не произошло. Я не хочу этого Из чтения это звучит так, как будто я хочу, чтобы ПОЛНЫЙ OUTER JOIN, но SQL Server Compact Edition не поддерживает FULL OUTER JOIN с. Есть ли способ обойти это, или я ищу что-то совсем другое?

Ответы [ 6 ]

40 голосов
/ 23 марта 2010

Попробуйте:

SELECT WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, 
    WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged,
    WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop
FROM indRailType
LEFT OUTER JOIN WO_BreakerRail ON indRailType.RailCode = WO_BreakerRail.RailCode 
            AND WO_BreakerRail.Date = @Date

Таким образом добавляя AND WO_BreakerRail.Date = @Date в объединение

15 голосов
/ 23 марта 2010

Условие предиката должно быть в предложении On для объединения, а не в предложении where. То, как работают внешние соединения, заключается в том, что после анализа условий соединения все строки с «внешней стороны», которые не соответствуют внутренней стороне, добавляются обратно в .... Но все это происходит до обработки предложения where. Поэтому, если предикат предложения where фильтрует атрибут с внешней стороны внешнего соединения, все эти строки будут удалены снова ... (Все они равны NULL). Вместо этого поместите предикат в условие соединения, тогда он будет оценен до того, как недостающие строки будут добавлены обратно в ...

SELECT b.ID, t.RailType, b.CreatedPieces, 
       b.OutsideSource, b.Charged, b.Rejected, 
       b.RejectedToCrop 
FROM indRailType t
   LEFT JOIN WO_BreakerRail b
        ON t.RailCode = b.RailCode 
            And b.Date = @Date
5 голосов
/ 23 марта 2010

Вы можете использовать это условие:

WHERE WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL
2 голосов
/ 23 марта 2010

добавьте WO_BreakerRail.Date = @Date в оператор LEFT OUTER JOIN, а не WHERE:

SELECT
    WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop
    FROM indRailType 
        LEFT OUTER JOIN WO_BreakerRail ON indRailType.RailCode = WO_BreakerRail.RailCode AND WO_BreakerRail.Date = @Date

или вы можете добавить его в ГДЕ:

SELECT
    WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop
    FROM indRailType 
        LEFT OUTER JOIN WO_BreakerRail ON indRailType.RailCode = WO_BreakerRail.RailCode
    WHERE (WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL)
1 голос
/ 18 июля 2013

или вы можете добавить его к WHERE:

SELECT WO_BreakerRail.ID, indRailType.RailType, 
  WO_BreakerRail.CreatedPieces, 
  WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, 
  WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop 
FROM indRailType, WO_BreakerRailCode 
WHERE indRailType.RailCode = WO_BreakerRail.RailCode(+) 
 AND WO_BreakerRail.Date (+) =@Date 
1 голос
/ 23 марта 2010

Вам нужно отфильтровать WO_BreakerRail до желаемой даты до ВЛЕВО, ПОДКЛЮЧАЯ к indRailType. Если вы просто добавите оператор WHERE, это будет сделано наоборот, что приведет к описанной вами проблеме.

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

SELECT R.ID, indRailType.RailType, R.CreatedPieces, R.OutsideSource, R.Charged, R.Rejected, R.RejectedToCrop
  FROM indRailType LEFT OUTER JOIN
       (SELECT * FROM WO_BreakerRail WHERE Date = @Date) R
       ON indRailType.RailCode = R.RailCode

(Не проверено, но, насколько мне известно, SQL Server CE поддерживает подзапросы.)

...