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 JOIN
s. y a-t-il un moyen de contourner cela, ou est-ce que je cherche autre chose entièrement?
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
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
Vous pouvez utiliser cette clause where:
WHERE WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL
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)
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.)
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