如何正确分组数据

时间:2012-06-15 14:47:29

标签: tsql group-by pivot cube rollup

我的最终目标是拥有一张如下表:

Maturity Band     AAA     AA     A    A-    BBB+     BBB-    BB+    BB   Total
Less Than 1 yr    2.63%   5%                2%                           9.63%
1 to 5 yrs                       5%         5%                           10%
5 to 10 yrs       5.00%                              5%                  10%
10 to 20 yrs                          2%                                 2%
More than 20 yrs  10%                                         6%    1%   17%
Total             17.63%   5%    5%   2%    7%       5%       6%    1%   48.63%

我创建的程序(@Worktable)中的表格如下所示:

PortfolioID    IssueName    SandPRating    SandPRatingSort    MaturityBand    MaturitySort
XXXXX          Bond1        AAA            1                  Less than 1 yr  1
XXXXX          Bond2        AAA            1                  Less than 1 yr  1
XXXXX          Bond3        AA-            7                  5 to 10 yrs     3
XXXXX          Bond4        BBB+           8                  1 to 5 yrs      2
etc.......

SandPRatingSort命令评级为1是最高的,并且对于成熟度排序是相同的。

我的问题是我在我的程序中将表格编码为上面的格式(对不起,如果这看起来很容易,但我对此相对较新)。我可以通过MaturityBand对其进行分组,但是我如何将其分成正确的顺序,以及如何使用评级作为标题来实现百分比?顺便说一下,百分比是指评级占投资组合持有的所有债券的百分比的债券数量。

到目前为止,我所做的最好的就是这个支点:

SELECT MaturityBand, [AAA],[AA+],[AA],[AA-],[A+],[A],[A-],[BBB+],[BBB],[BBB-],[BB+],[BB],[BB-],[B+],[B],[B-],[CCC+],[CCC],[CCC-],[CC],[C],[DDD],[DD],[D],[N.R.],[N.A.],[WR]
FROM
(
SELECT
MaturityBand
,SandPRating
FROM @Worktable
WHERE SandPRating IS NOT NULL
GROUP BY MaturityBand, SandPRating, MaturitySort, SandPSort
) AS source
PIVOT
(
COUNT(SandPRating)
FOR SandPRating IN ([AAA],[AA+],[AA],[AA-],[A+],[A],[A-],[BBB+],[BBB],[BBB-],[BB+],[BB],[BB-],[B+],[B],[B-],[CCC+],[CCC],[CCC-],[CC],[C],[DDD],[DD],[D],[N.R.],[N.A.],[WR])
) AS pvt

枢轴并没有完全按照我想做的去做。我如何获得百分比?如何获得列和行的总计?此外,枢轴中的计数仅返回1,如何在不对工作台进行全部工作的情况下对每列的额定值进行求和?

正确方向上的一点或一些指导将会大大增加。

由于

2 个答案:

答案 0 :(得分:1)

通过一些试验和错误以及其他帖子的一些帮助,我设法回答了我自己的问题。 CTE非常有用,我很高兴我有这方面的经验,能够了解它的细节。

;WITH CTE
AS
(
SELECT  PortfolioID
        , MaturityBand
        , SandPRating
        , MaturitySort
        , SUM((1/RecNo)*100) AS Pct

FROM    @Worktable AS A
--WHERE SandPRating IS NOT NULL
Group by MaturitySort, MaturityBand, SandPRating, PortfolioID

UNION All

SELECT   PortfolioID
        , MaturityBand
        , 'SandPRating_Total' AS SandPRating
        , MaturitySort
        , COUNT(*) * 100.0
        /
        (
            SELECT COUNT(*)
            FROM     @Worktable AS B
            WHERE B.PortfolioID = A.PortfolioID
        ) AS Total_Pct
FROM    @Worktable AS A
--WHERE SandPRating IS NOT NULL 
GROUP BY  MaturitySort, MaturityBand, PortfolioID
)
, CTE2
AS
(
SELECT  Grouping_ID(SandPRating, MaturityBand, MaturitySort) AS ID

     , CASE 
        WHEN Grouping_ID(SandPRating, MaturityBand, MaturitySort) = 3 THEN 'Total' 
        ELSE MaturityBand 
       END                                              AS MaturityBand

     , SandPRating

     , CASE 
        WHEN Grouping_ID(SandPRating, MaturityBand, MaturitySort) = 3 THEN 1000 
        ELSE MaturitySort 
       END                                              AS MaturitySort

     , SUM(Pct) AS PCT

FROM    CTE
GROUP BY ROLLUP (SandPRating
     , MaturityBand
     , MaturitySort)
)
--PIVOT
SELECT  MaturityBand, [AAA],[AA+],[AA],[AA-],[A+],[A],[A-]
    ,[BBB+],[BBB],[BBB-],[BB+],[BB],[BB-],[B+],[B],[B-]
    ,[CCC+],[CCC],[CCC-],[CC],[C],[DDD],[DD],[D],[N.R.]
    ,[N.A.],[WR],[Unass],[SandPRating_Total]     
FROM    (   SELECT SandPRating, MaturityBand, MaturitySort, PCT 
        FROM Cte2
        WHERE   ID = 0 or ID = 3
    ) AS x

PIVOT   (SUM(PCT)
        FOR SandPRating
        IN  ([AAA],[AA+],[AA],[AA-],[A+],[A],[A-]
            ,[BBB+],[BBB],[BBB-],[BB+],[BB],[BB-],[B+],[B],[B-]
            ,[CCC+],[CCC],[CCC-],[CC],[C],[DDD],[DD],[D],[N.R.]
            ,[N.A.],[WR],[Unass],[SandPRating_Total])
    ) myPiv
ORDER BY MaturitySort

答案 1 :(得分:0)

以下内容获取所有项目并计算所有项目的百分比值:

SELECT *
FROM (
  SELECT
    MaturitySort = COALESCE(MaturitySort, 2147483647),
    MaturityBand = COALESCE(MaturityBand, 'Total'),
    SandPRating  = COALESCE(SandPRating , 'Total'),
    [Percent]    =
      COUNT(*) * 100.0 /
      SUM(CASE WHEN MaturityBand IS NOT NULL AND SandPRating IS NOT NULL THEN COUNT(*) END) OVER ()
  FROM WorkTable
  GROUP BY
  CUBE(
    (MaturityBand, MaturitySort),
    (SandPRating)
  )
) s
PIVOT (
  MAX([Percent]) FOR SandPRating IN (
    [AAA],[AA+],[AA],[AA-],[A+],[A],[A-],
    [BBB+],[BBB],[BBB-],[BB+],[BB],[BB-],[B+],[B],[B-],
    [CCC+],[CCC],[CCC-],[CC],[C],[DDD],[DD],[D],[N.R.],
    [N.A.],[WR],[Unass],[Total]
  )
) p
ORDER BY MaturitySort

如您所见,百分比值的计算使用聚合窗口函数(SUM())。如果CUBE()没有分组,我们就可以SUM(COUNT(*)) OVER ()。但是对于CUBE(),它将包括不应包含的值(卷起的计数)。考虑它们的一种方法是对NULL进行SandPRatingMaturityBand测试,因为当行包含累计计数时,NULL将替换其中一列或两列。

当然,这假定两个列{,1}都不能保存实际的NULL。省略汇总的更合适的方法可能是测试MaturityBand的结果:如果它为两列返回GROUPING(column),请在总数中包含0

COUNT(*)