web-dev-qa-db-ja.com

GROUP BY SQL Server後の合計SUMからの割合

私はこれらの結果があります:

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フィドル http://sqlfiddle.com/#!9/80f91/2

9
Ryan Gadsdon

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は整数除算を行います。 10進数を使用してこのような計算を行うため、より理にかなっています。

ここ はSQL Fiddleであり、2つの変更があります。

  1. データベースがSQL Serverに変更されます。
  2. 合計は文字列ではなく数値として保存されます。
20
Gordon Linoff

共通テーブル式を使用できます...

;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
2
Gowtham Alan

他の人が言ったように、CTEを使用して問題を解決できます。私の場合は、CROSS JOINを使用せず(特別な理由なし)、CTEを2回行いました。また、ゼロ除算エラーの可能性を防ぐためにNULLIFをスローしました(代わりにNULLが発生します)。

また、PackageテーブルのTotal列は、列の合計または計算を実行するたびに、数値型(特定の「数値」型ではなく、 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
1
KnarfaLingus

以下のコードを試してください

;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%
1
Sreenu131