web-dev-qa-db-fra.com

Pourcentage de la somme totale après GROUP BY SQL Server

J'ai ces résultats:

PersonID    SUM(PA.Total)
-------------------------
   1            75
   2            75
   3            15
   4            15
   5            60
   6            60

Avec la table comme:

PersonID    Total
------------------
   1         50
   2         50
   3         10
   4         10
   5         40
   6         40
   1         25
   2         25
   3          5
   4          5
   5         20
   6         20

Ceux-ci sont regroupés par personne. Maintenant, je cherche à ajouter une colonne avec les pourcentages pour chaque personne calculée à partir du total de toutes leurs sommes.

Par exemple: la somme totale est 300, et j’ai donc besoin d’un résultat comme celui-ci:

PersonID    SUM(PA.Total)   Percentage
--------------------------------------
   1            75              25%
   2            75              25%
   3            15              5%
   4            15              5%
   5            60              20%
   6            60              20%

J'ai examiné le code en ligne et j'ai trouvé une solution comme celle-ci:

 SELECT 
     P.PersonID, SUM(PA.Total)
     SUM(PA.Total) * 100 / [p] AS 'Percentage'
 FROM 
     Person P
 JOIN 
     Package PA ON P.PersonID = PA.PackageFK
 CROSS JOIN 
     (SELECT SUM(PA.[Total]) AS [p] 
      FROM Package PA) t
 GROUP BY 
     P.PersonID

Mais je ne sais pas comment incorporer la jointure croisée dans la jointure ainsi que la section déjà groupée/somme. Ou si cela va tout à fait dans le bon sens.

Toute aide serait la bienvenue - SQL fiddle http://sqlfiddle.com/#!9/80f91/2

5
Ryan Gadsdon

Vous n'avez pas besoin d'un cross join. Il suffit d'utiliser les fonctions de la fenêtre:

SELECT P.PersonID, SUM(PA.Total),
       SUM(PA.Total) * 100.0 / SUM(SUM(PA.Total)) OVER () AS Percentage
FROM Person P JOIN
     Package PA
     ON P.PersonID = PA.PackageFK
GROUP BY P.PersonID;

Notez que vous n'avez pas besoin de la variable JOIN pour cette requête:

SELECT PA.PersonID, SUM(PA.Total),
       SUM(PA.Total) * 100.0 / SUM(SUM(PA.Total)) OVER () AS Percentage
FROM Package PA
GROUP BY PA.PersonID;

SQL Server effectue une division entière. Je fais de tels calculs en utilisant des nombres décimaux pour qu'ils aient plus de sens.

Ici est un violon SQL, avec deux modifications:

  1. La base de données est remplacée par SQL Server.
  2. Le total est stocké sous forme de nombre plutôt que de chaîne.
11
Gordon Linoff

Vous pouvez utiliser Common table Expression ...

;with cte as(
  select  P.PersonID,SUM(cast(PA.Total as int))Total  from  Package PA join   Person P on P.PersonID = PA.PackageFK GROUP BY P.PersonID 
  )
  select PersonId,Total,cast (Total * 100 / t.GrandTotal as varchar) + '%'  [Percentage] from cte cross join(select SUM(cast(Total as int)) as GrandTotal from Package)t
3
Gowtham Alan

Comme les autres l'ont dit, vous pouvez utiliser le CTE pour résoudre le problème. Le mien est un peu différent en ce sens que je n'ai pas utilisé de CROSS JOIN (pas de raison particulière) et que j'ai fait un double CTE. De plus, j'ai jeté un NULLIF dans pour éviter les erreurs possibles de division par zéro (le résultat sera NULL). 

En outre, la colonne Total de la table de packages doit être un type numérique (pas le type spécifique "numérique", mais un type de colonne pouvant contenir nombres ), chaque fois que vous faites la somme ou que vous effectuez des calculs sur une colonne. hors il devrait être numérique.

;WITH PersonTotals AS
(
  SELECT P.PersonID, SUM(CAST(PA.Total AS MONEY)) Total
  FROM Person P
  JOIN Package PA ON P.PersonID = PA.PackageFK
  GROUP BY P.PersonID
),
GrandTotal AS
(
  SELECT SUM(PT.Total) Total
  FROM PersonTotals PT
)
SELECT PT.*, (PT.Total / NULLIF((SELECT Total From GrandTotal),0)) * 100 Percentage
FROM PersonTotals PT
1
KnarfaLingus

Essayez ce code ci-dessous

;With cte(PersonID ,Total)
AS
(
 SELECT  1 ,75 UNION ALL
 SELECT  2 ,75 UNION ALL
 SELECT  3 ,15 UNION ALL
 SELECT  4 ,15 UNION ALL
 SELECT  5 ,60 UNION ALL
 SELECT  6 ,60
 )

SELECT PersonID, 
       Total, 
       CAST(CAST((MAX(total)OVER(partition BY personid ORDER BY total)*100.0/ 
       MaxSum) AS INT)AS VARCHAR(5))+ '%' AS Percentage 
FROM   (SELECT personid, 
               total, 
               stotal, 
               Max(stotal) 
                 OVER( 
                   ORDER BY stotal DESC) AS MaxSum 
        FROM   (SELECT personid, 
                       total, 
                       Sum(total) 
                         OVER( 
                           ORDER BY personid) AS STotal 
                FROM   Cte)dt 
        GROUP  BY dt.personid, 
                  dt.total, 
                  dt.stotal)dt2 
ORDER  BY dt2.personid ASC 

Résultat

PersonID    Total   Percentage
------------------------------
1            75         25%
2            75         25%
3            15         5%
4            15         5%
5            60         20%
6            60         20%
1
Sreenu131