2010-11-16 7 views
1

Google ne m'a pas aidé ici et n'a pas encore d'aide en ligne Microsoft.LEFT JOIN sur les tables en ligne

J'ai des tables Inline qui sont générées en tant que sous-requête. (Voir le code simplifié ci-dessous, j'ai plusieurs autres tables en ligne.)

Maintenant, c'est très bien où j'ai des données. Cependant, il y a des cas où je dois retourner des résultats quand il n'y a pas de données. Par exemple, Inline table 1 renvoie mon nombre de clients actifs ... Si je spécifie une plage où il n'y a pas de clients actifs, je n'obtiens aucun résultat pour l'ensemble de la requête.

Cela est dû à mon join (ET = IL1.transaction_id th.transaction_id)

Comment puis-je joindre à la table à gauche en ligne?

J'ai essayé LEFT JOIN IL1 sur il1.transaction_id = th.transaction_id mais il dit que la table n'existe pas.

select SUM(th.total_net_retail_central) as 'Net Purchases TY', 
      IL1.Active as 'Number of Active Customers TY', 
      COUNT(th.transaction_id) as 'Number of Transactions TY' 

FROM   

(SELECT transaction_type, COUNT(DISTINCT customer_id) as 'Active' from transaction_header 
where transaction_date BETWEEN @Active and @ToDate group by transaction_type)IL1, 
transaction_header th 

INNER JOIN transaction_type tt ON th.transaction_type = tt.transaction_type 
WHERE 
th.transaction_date Between @FromDate AND @ToDate 

AND   IL1.transaction_type = th.transaction_type 

GROUP BY 
      tt.transaction_type_description, IL1.Active 

Toute aide est vraiment appréciée.

+0

"ENTRE @Active et @ToDate" semble mal là-bas. –

+0

Pouvez-vous poster la requête que vous avez essayé avec la jointure gauche qui n'a pas fonctionné s'il vous plaît? – StevenWilkins

+0

Cela fonctionne comme si, par exemple, ma date est le 1er janvier, ma date est le 30 octobre et ma date active est le 5 avril, je reçois nombre de clients actifs entre le 5 avril et le 30 octobre, mais mes autres résultats vont du 1er janvier au 30 octobre. Cependant, s'il n'y a pas eu de cutomers actifs cela va générer un null et ma jointure sera nulle donc je n'obtiens aucun résultat globalement ... vous voyez? –

Répondre

2

Vous ne devez pas mélanger des jointures implicites et explicites, vous risquez d'obtenir des résultats incohérents. Aussi franchement, vous ne devriez jamais utiliser une jointure implicite.

Voir si cela fonctionne pour vous:

SELECT SUM(th.total_net_retail_central) AS 'Net Purchases TY', 
      COALESCE(IL1.Active, 0) AS 'Number of Active Customers TY', 
      COUNT(th.transaction_id) AS 'Number of Transactions TY' 

FROM  transaction_header th  
INNER JOIN transaction_type tt 
    ON th.transaction_type = tt.transaction_type 
LEFT JOIN (SELECT transaction_type, COUNT(DISTINCT customer_id) AS 'Active' 
      FROM transaction_header 
      WHERE transaction_date BETWEEN @Active and @ToDate 
      GROUP BY transaction_type)IL1 
    ON IL1.transaction_type = th.transaction_type 
WHERE th.transaction_date BETWEEN @FromDate AND @ToDate 
GROUP BY tt.transaction_type_description, COALESCE(IL1.Active, 0) 
+0

Ceci est intéressant .. J'avais regardé CTE (comme dans la réponse précédente) mais j'ai oublié de mentionner l'une des machines fonctionne SQL 2000. COALESCE pourrait être utile. Je vais donner un coup de feu aussi, merci beaucoup pour votre contribution. –

+0

Droit ... généralement (quand il y a des données dans tous les paramètres) ma requête prend environ 49 secondes pour s'exécuter. J'ai changé les tables IL en jointures LEFT et maintenant ma requête a fonctionné pendant plus de 10 minutes sans retourner de données. Je pense qu'il y a un problème. Je vais essayer d'isoler la cause. Merci beaucoup. –

+0

Je dirais qu'il y a définitivement un problème. – HLGEM

1
select SUM(th.total_net_retail_central) as 'Net Purchases TY', 
      IL1.Active as 'Number of Active Customers TY', 
      COUNT(th.transaction_id) as 'Number of Transactions TY' 
FROM   
(SELECT transaction_type, 
     COUNT(DISTINCT customer_id) as 'Active' 
     from transaction_header 
    where transaction_date BETWEEN @Active and @ToDate 
    group by transaction_type) IL1 
    right join 
       transaction_header th 
       on IL1.transaction_type = th.transaction_type 
INNER JOIN transaction_type tt 
      ON th.transaction_type = tt.transaction_type 
WHERE 
th.transaction_date Between @FromDate AND @ToDate 
GROUP BY 
      tt.transaction_type_description, IL1.Active 

Si je lis cela, je crois bien que vous avez besoin d'un RIGHT JOIN entre IL1 et TH

IL1 jointure droite transaction_header th sur IL1.transaction_type = th.transaction_type

+0

@HLGEM réponse est plus maintenable (car il semble plus facile à lire et donc maintenir les jointures internes en haut et ensuite la jointure à gauche à la fin au lieu de commencer par une jointure à DROITE - J'essayais juste de partir l'instruction seule autant que possible) – Harrison

3

Depuis que vous exécutez SQL Server 2005, je vais utiliser un CTE pour nettoyer un peu.

;with cteIL1 as (
    SELECT transaction_type, COUNT(DISTINCT customer_id) as 'Active' 
     from transaction_header 
     where transaction_date BETWEEN @Active and @ToDate 
     group by transaction_type 
) 
select SUM(th.total_net_retail_central) as 'Net Purchases TY', 
     ac.Active as 'Number of Active Customers TY', 
     COUNT(th.transaction_id) as 'Number of Transactions TY' 
    FROM transaction_header th 
     INNER JOIN transaction_type tt 
      ON th.transaction_type = tt.transaction_type 
     LEFT JOIN cteIL1 IL1 
      on th.transaction_type = IL1.transaction_type 
    WHERE th.transaction_date Between @FromDate AND @ToDate 
    GROUP BY tt.transaction_type_description, IL1.Active  

EDIT: Version non-CTE pour 2000 tel que mentionné dans les commentaires:

select SUM(th.total_net_retail_central) as 'Net Purchases TY', 
     ac.Active as 'Number of Active Customers TY', 
     COUNT(th.transaction_id) as 'Number of Transactions TY' 
    FROM transaction_header th 
     INNER JOIN transaction_type tt 
      ON th.transaction_type = tt.transaction_type 
     LEFT JOIN (SELECT transaction_type, COUNT(DISTINCT customer_id) as 'Active' 
         from transaction_header 
         where transaction_date BETWEEN @Active and @ToDate 
         group by transaction_type 
        ) IL1 
      on th.transaction_type = IL1.transaction_type 
    WHERE th.transaction_date Between @FromDate AND @ToDate 
    GROUP BY tt.transaction_type_description, IL1.Active  
+0

Je vois ... J'ai regardé dans CTE mais j'aurais dû le mentionner (alors que la requête que je développe est sur une boîte de SQL Server 2005) l'une des machines sur lesquelles il sera utilisé est SQL 2000 ... Cependant, je peux intégrer le CTE dans les machines SQL 2005 .. Je vais essayer. Merci pour votre contribution –

+0

@Wes Prix: Pour la boîte 2000, il suffit de déplacer à nouveau le SELECT du CTE en ligne. Voir ma réponse éditée. –

+0

Ah je vois. Fantastique ... Je pense que j'ai peut-être mal compris comment une jointure gauche améliorerait ma syntaxe. Certaines de mes tables en ligne peuvent être vides. Si j'essaye de me joindre à la table vide, cela prend un temps exponentiel pour faire n'importe quoi. Sais-tu comment je m'en souviendrais? Merci beaucoup –