【问题标题】:Percentage from Total SUM after GROUP BY SQL ServerGROUP BY SQL Server 后总和的百分比
【发布时间】:2018-04-05 04:33:47
【问题描述】:

我有这些结果:

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

像这样的表:

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

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

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

【问题讨论】:

    标签: sql sql-server join sum percentage


    【解决方案1】:

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

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

    Here 是一个 SQL Fiddle,有两个变化:

    1. 数据库已更改为 SQL Server。
    2. 总数存储为数字而不是字符串。

    【讨论】:

    • 谢谢!我确实需要在我的实际代码中加入,但这只是一个示例
    • 不错,SUM(SUM(PA.Total)) OVER ()
    【解决方案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%
    

    【讨论】:

      【解决方案3】:

      您可以使用公用表表达式...

      ;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
      

      【讨论】:

        【解决方案4】:

        就像其他人说的,你可以使用 CTE 来解决问题,我的有点不同,我没有使用 CROSS JOIN(没有特殊原因),而是做了双重 CTE。我还扔了一个 NULLIF 以防止可能的除以零错误(将导致 NULL 代替)。

        此外,Package 表 Total 列应该是数字类型(不是特定的“数字”类型,而是可以容纳 numbers 的列类型),只要您对列求和或执行数学运算,这就是一个提示-off 它应该是数字。

        ;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
        

        【讨论】:

          【解决方案5】:

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

          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;
          

          这将由办公室给出一个总数。

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

          【讨论】:

            【解决方案6】:

            简单

            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;
            

            【讨论】:

            • 这不是循环查询吗?不确定它会起作用。我认为前面提到的窗口函数或 CTE 是前进的方向。
            猜你喜欢
            • 2019-02-12
            • 1970-01-01
            • 1970-01-01
            • 2016-07-02
            • 1970-01-01
            • 2014-02-19
            • 2013-05-31
            • 2020-07-25
            • 1970-01-01
            相关资源
            最近更新 更多