Jointure externe gauche avec une clause WHERE

J'ai deux tables. indRailType contient une liste des noms associés à une valeur D'ID que j'utilise dans d'autres tables pour indiquer le type de rail. WO_BreakerRail contient une colonne de date et une colonne de code ferroviaire qui correspond au même code dans indRailType et d'autres données. Il y a une ligne dans WO_BreakerRail pour toute activité sur chaque type de rail, pour chaque date. Donc, je pourrais avoir 3 lignes datées pour 3/19/2010, chaque ligne indique un code ferroviaire différent, et ce qui s'est passé.

Lorsque j'utilise le LEFT OUTER JOIN suivant, j'obtiens une table avec tous les types de rails, avec des valeurs NULL dans les rangées où rien ne s'est passé le 19. Maintenant, cela ne fonctionne que parce que je n'ai qu'une seule date représentée dans ma table WO_BreakerRail en ce moment, le 19. Quand j'ajoute plus de lignes avec des dates différentes, les choses vont dégénérer.

C'est ma déclaration SQL, qui me donne maintenant exactement les résultats que je veux:

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

Maintenant, quand j'ajoute une clause WHERE WO_BreakerRail.Date = @Date, je perds toutes les lignes du JOIN dont rien ne s'est passé. Je n'en veux pas. De la lecture, de la il on dirait qu'un OUTER JOIN complet est ce que je veux, mais SQL Server Compact Edition ne supporte pas FULL OUTER JOINs. y a-t-il un moyen de contourner cela, ou est-ce que je cherche autre chose entièrement?

21
demandé sur Michał Powaga 2010-03-23 18:14:05

6 réponses

Essayez:

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

Ajoutant ainsi AND WO_BreakerRail.Date = @Date sur la jointure

39
répondu Philip Fourie 2013-01-19 06:53:55

La condition de prédicat doit être dans la clause On pour la jointure, pas dans la clause where. La façon dont les jointures extérieures fonctionnent, c'est après que les conditions de jointure sont analysées, toutes les lignes du "côté extérieur" qui ne correspondent pas au côté intérieur sont ajoutées.... Mais tout cela se produit avant que la clause where ne soit traitée. Donc, si le prédicat de clause where filtre sur un attribut du côté externe d'une jointure externe, toutes ces lignes seront à nouveau supprimées... (Ils sont tous nuls). Mettez le prédicat dans la condition de jointure à la place, elle sera évaluée avant que les lignes manquantes ne soient ajoutées...

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
15
répondu Charles Bretana 2010-03-23 15:22:28

Vous pouvez utiliser cette clause where:

WHERE WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL
5
répondu Andrew Bezzub 2010-03-23 15:17:13

Ajouter le WO_BreakerRail.Date = @Date sur LEFT OUTER JOIN instruction et non l' 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

Ou vous pouvez l'ajouter au 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
    WHERE (WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL)
2
répondu KM. 2010-03-23 15:16:32

Ce que vous voulez, c'est filtrer votre WO_BreakerRail à la date souhaitée avant que ne le rejoigne à indRailType. Si vous ajoutez simplement L'instruction WHERE, cela se fait dans l'autre sens, ce qui entraîne le problème que vous avez décrit.

Les solutions fournies jusqu'à présent devraient fonctionner (déplacer la condition dans la jointure de gauche), mais je voudrais suggérer une alternative: vous pouvez utiliser une sous-requête pour spécifier l'ordre dans lequel les choses doivent être faites:

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

(non testé, mais pour autant que je sache, SQL Server CE prend en charge les sous-requêtes.)

1
répondu Heinzi 2010-03-23 15:23:13

Ou vous pouvez l'ajouter à la 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
répondu Nilanjan Pal 2013-07-18 11:25:07