2009-07-08 15 views
3

J'ai deux tables, une avec toutes mes branches, et une avec toutes mes ventes. La table des ventes contient également un ID de représentant des ventes, un ID de succursale, un mois et une année.T-SQL, somme nulle pour aucune correspondance à la jointure

J'ai besoin d'une requête qui retourne la somme des ventes d'un représentant spécifique pour une année, regroupées par branche et mois, et la requête doit retourner 0 s'il n'y a pas eu de ventes dans une succursale pour ce mois. J'ai ce qui suit, qui ne retourne pas 0 s'il n'y a pas de vente:

SELECT 
    s.Month, 
    b.BranchName, 
    SUM(s.InvoiceAmount) AS 'Sales' 
FROM 
    Branch b 
INNER JOIN 
    Sales s ON s.BranchID = b.BranchID 
WHERE 
    s.Year = 2008 
AND 
    s.SalesRepID= 11 
GROUP BY 
    s.Month, 
    b.BranchName 
ORDER BY 
    s.Month, 
    b.BranchName 
+0

Êtes-vous absent à partir de la liste SELECT? – pjp

+0

Mon erreur, oui le s.Month est dans le SELECT – staterium

+0

(corrigé dans OP) – staterium

Répondre

4

Vous aurez besoin d'ajouter les données "manquantes" pour pouvoir le rejoindre.

SELECT 
    b.BranchName, 
    SUM(ISNULL(s.InvoiceAmount, 0)) AS 'Sales', 
    s.Month 
FROM 
    Branch b 
    LEFT OUTER JOIN (
      SELECT 
     b.BranchID AS BranchID 
     , s.SalesRepID AS SalesRepID 
     , Months.Month AS Month 
     , Years.Year AS Year 
     , 0 AS InvoiceAmount 
     FROM 
      Sales s 
      CROSS JOIN (
      SELECT 1 AS Month 
      UNION ALL SELECT 2 
      UNION ALL SELECT 3 
      UNION ALL SELECT 4 
      UNION ALL SELECT 5 
      UNION ALL SELECT 6 
      UNION ALL SELECT 7 
      UNION ALL SELECT 8 
      UNION ALL SELECT 9 
      UNION ALL SELECT 10 
      UNION ALL SELECT 11 
      UNION ALL SELECT 12 
      ) Months 
      CROSS JOIN (
      SELECT 2007 AS Year 
      UNION ALL SELECT 2008 
      UNION ALL SELECT 2009 
      ) Years 
      CROSS JOIN Branch b 
     UNION ALL SELECT 
     s.BranchID AS BranchID 
     , s.SalesRepID AS SalesRepID 
     , s.Month AS Month 
     , s.Year AS Year 
     , s.InvoiceAmount AS InvoiceAmount 
     FROM Sales s  
    )s ON s.BranchID = b.BranchID  
WHERE 
    s.Year = 2008 
    AND s.SalesRepID= 11 
GROUP BY 
    s.Month, 
    b.BranchName 
ORDER BY 
    b.BranchName, 
    s.Month 
+0

J'étais sur le point de poster quelque chose de similaire – pjp

+1

heureux d'entendre que je ne suis pas seul dans la façon dont j'ai interprété la question. Toutes les autres réponses semblent se concentrer sur les valeurs NULL dans InvoiceAmount. Je doute que c'est ce que l'OP voulait dire. –

+0

Merci Lieven, ça marche (en quelque sorte). Je reçois maintenant 0 valeurs pour les mois où le représentant n'a pas de ventes dans cette branche, mais la requête dans son ensemble ne renvoie que les succursales où le représentant a eu des ventes à un moment donné dans l'année. – staterium

2

Vous devez faire un LEFT JOIN aux ventes, de façon à revenir même les représentants qui n'ont pas de dossiers dans le Table de vente.

+0

La jointure gauche devrait ajouter ces branches sans ventes apparaissent dans la requête finale et l'agrégat retournera alors pour eux. – Spence

+0

-1 Il y a une clause where sur s.SalesRepId et donc une jointure externe gauche sur Sales serait inutile. – pjp

1

Si votre requête retourne NULL, vous pouvez utiliser l'une des méthodes coalescents: COALESCE(SUM(...), 0) retourne la première valeur non NULL dans la liste ...

+0

Ne devrait pas coalesce être dans la somme. Ou la somme peut être supérieure aux valeurs NULL. Je crois que cela soulève un avertissement dans SQL sever. – pjp

+0

Avertissement: La valeur nulle est éliminée par un agrégat ou une autre opération SET. (1 ligne (s) affectée (s)) – pjp

0

j'ai changé la jointure de l'intérieur vers extérieur gauche et a ajouté la fonction ISNULL pour les succursales sans vente.

SELECT 

    b.BranchName, 
    s.Month, 
    SUM(ISNULL(s.InvoiceAmount,0)) AS 'Sales' 
FROM 
    Branch b 
LEFT JOIN 
    Sales s ON s.BranchID = b.BranchID 
WHERE 
    s.Year = 2008 
AND 
    s.SalesRepID= 11 
GROUP BY 
    s.Month, 
    b.BranchName 
ORDER BY 
    s.Month, 
    b.BranchName 
+0

La question demande le chiffre d'affaires par mois même s'il n'y a pas de ventes au cours d'un mois donné. Cette requête renvoie les résultats pour l'année entière. – pjp

+0

Cela n'a pas changé mon résultat. – staterium

0

Vous devez utiliser une jointure gauche et un isnull pour obtenir la somme droite:

SELECT b.BranchName 
, SUM(isnull(s.InvoiceAmount, 0)) AS 'Sales' 
FROM  Branch b 
LEFT JOIN Sales s ON s.BranchID = b.BranchID 
GROUP BY  s.Month, b.BranchName 
ORDER BY  s.Month, b.BranchName 

Vous avez encore besoin de faire un peu plus de travail avec elle pour obtenir les mois montrant aussi si un vendeur a pas de ventes dans un mois particulier.