2010-03-23 7 views
18

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 de rail qui correspond au même code dans indRailType et quelques autres données. Il y a une ligne WO_BreakerRail pour chaque 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 est arrivé. Lorsque j'utilise le LEFT OUTER JOIN suivant, j'obtiens une table avec tous les types de rails, avec des zéros dans les lignes où rien ne s'est passé le 19ème. Maintenant, cela ne fonctionne que parce que j'ai seulement une date représentée dans ma table WO_BreakerRail en ce moment, le 19ème. Lorsque j'ajoute plus de lignes avec des dates différentes, les choses vont se détraquer.LEFT OUTER JOIN avec une clause WHERE

Ceci est mon instruction SQL, qui droit 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 dans une clause WHERE WO_BreakerRail.Date = @Date je perds toutes les lignes de la JOIN qui ne se passait rien. Je ne veux pas ça. De la lecture, cela ressemble à un plein OUTER JOIN est ce que je veux, mais SQL Server Compact Edition ne prend pas en charge FULL OUTER JOIN s. Y a-t-il un moyen de contourner cela, ou est-ce que je cherche autre chose?

Répondre

35

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

+1

N'oubliez pas de prendre en compte la partie "time" de @Date. Si les valeurs peuvent varier entre minuit et minuit, vous devrez utiliser une clause between between. –

+0

Cette réponse a parfaitement fonctionné, merci. Philip: Merci pour ce pointeur, bien que j'ai rencontré ce problème plus tôt dans ce projet qui m'a bloqué pendant un certain temps, mais j'ai fini par le corriger dans mon code C#, supprimant toutes les portions de temps, par défaut à minuit. – Wesley

+1

@Wesley, il est préférable de "plancher" les types de données datetime pour supprimer l'heure, de sorte que l'heure est 00: 00: 00.000 et non minuit. –

2

ajouter le WO_BreakerRail.Date = @Date sur la déclaration LEFT OUTER JOIN et non le 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 à la OÙ:

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) 
5

Vous pouvez utiliser cette clause where:

WHERE WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL 
+3

Lorsque vous travaillez avec les jointures externes, il est préférable de f l'acteur any "isnull work" dans la clause ON, et non la clause where –

15

La condition sous-jacente doit être dans la clause On pour la jointure, et non pas dans la clause where. La façon dont les jointures Outer fonctionnent, après que les conditions de jointure ont été analysées, toutes les lignes du "côté externe" qui ne correspondent pas au côté interne sont rajoutées dans .... Mais tout cela se passe 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 ... (Elles sont toutes nulles). Mettez le prédicat dans la condition de jointure au lieu, il va s'évalué avant les lignes manquantes sont réintégré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 
0

Ce que vous voulez est de filtrer votre WO_BreakerRail à la date souhaitée avant GAUCHE entreraient dans cette catégorie à 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 à ce jour devrait fonctionner (déplacer la condition dans le LEFT JOIN), mais je voudrais proposer une alternative: Vous pouvez utiliser une sous-requête pour spécifier l'ordre dans lequel les choses devraient se faire:

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, cE SQL Server prend en charge les sous-requêtes.)

1

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 (+) [email protected] 
+0

Le '(+)' est un opérateur de jointure Oracle et l'OP utilise SQL-Server. De plus, cette syntaxe pour les jointures externes n'est pas recommandée car elle est plus limitée et plus difficile à lire que la syntaxe 'Left Join' standard. [Oracle Docs: Jointures] (https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries006.htm) – Wayne