GROUP BY SQL 服务器后总和的百分比

Percentage from Total SUM after GROUP BY SQL Server

我有这些结果:

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

与table一样:

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

这些按人分组。现在我想添加一个列,其中包含根据每个人的总和计算得出的每个人的百分比。

例如:总和为300,因此我需要这样的结果:

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

我查看了在线代码并提出了如下修复方法:

 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

但我不确定如何将交叉联接合并到联接以及已经 group/sum 的部分中。或者这是否完全正确。

如有任何帮助,我们将不胜感激 - SQL fiddle http://sqlfiddle.com/#!9/80f91/2

您不需要 cross join。只需使用 window 函数:

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;

请注意,此查询不需要 JOIN

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 服务器做整数除法。我使用十进制数进行此类计算,因此它们更有意义。

Here 是 SQL Fiddle,有两个变化:

  1. 数据库更改为SQL服务器。
  2. 总计存储为数字而不是字符串。

试试下面的代码

;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 

结果

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

您可以使用通用 table 表达式...

;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

正如其他人所说,您可以使用 CTE 来解决问题,我的有点不同,因为我没有使用 CROSS JOIN(没有特殊原因)并且做了双 CTE。我还加入了一个 NULLIF 以防止可能的被零除错误(将导致 NULL)。

此外,Package table Total 列应该是数字类型(不是特定的 "numeric" 类型,而是可以容纳 numbers 的列类型),任何时候你都在求和或在列上执行数学运算,提示它应该是数字。

;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

添加到所选答案后,您可以添加另一个变量以进一步分割 %,例如一个人的办公室

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

这将由办公室给出总数。

发布为新答案而不是评论以提高可见度。

不复杂

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

没有JOIN

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