【问题标题】:SQL cumulative % TotalSQL 累计百分比总计
【发布时间】:2012-08-28 13:52:39
【问题描述】:

我的数据集如下所示:

COLA  | COLB
Name1 | 218
Name2 | 157
Name3 | 134
Name4 | 121

我需要这个输出:

COLA  | COLB| COLC
Name1 | 218 | 0.34
Name2 | 157 | 0.60
Name3 | 134 | 0.71
Name4 | 121 | 1

到目前为止,我的 SQL 是这样的:

SELECT COLA, COLB, COLB/SUM(COLB) FROM #MyTempTable

这个 SQL 有两个问题。一,COLC每次都是0,我不明白。第二,即使它确实导致了 %,它也不是累积的 %。

我在 StackOverflow 上看到了一些类似的线程,但我无法让这些线程的答案在我的确切场景中起作用。

提前感谢您的任何建议!

【问题讨论】:

  • 您需要一列来对行进行排序。你怎么知道哪一行在序列中排在第一位?
  • 确保在 SO 上发布 SQL 问题时,包括您正在使用的 RDBMS。 (MySQL?MSSQL?Oracle?)
  • #MyTempTable 表示法是否意味着 MS SQL Server?不过,我们不必猜测。
  • SQL 2008 - 很抱歉之前没有澄清这一点

标签: sql sql-server-2008 cumulative-sum


【解决方案1】:

我认为您正在寻找类似的东西,尽管您的示例计算可能有点偏离:

SELECT
    COLA,
    COLB,
    ROUND(
        -- Divide the running total...
        (SELECT CAST(SUM(COLB) AS FLOAT) FROM #MyTempTable WHERE COLA <= a.COLA) /
        -- ...by the full total
        (SELECT CAST(SUM(COLB) AS FLOAT) FROM #MyTempTable),
        2
    ) AS COLC
FROM #MyTempTable AS a
ORDER BY COLA

编辑:我添加了舍入。

这给了我们以下输出:

COLA    COLB    COLC
Name1   218     0.35
Name2   157     0.6
Name3   134     0.81
Name4   121     1

您的结果为 0(或 1)的原因是因为您将整数除以整数,从而给您一个整数(请参阅Datatype precedence)。

更新:

我应该补充一点,这使用“triangular join”来获得运行总数(WHERE COLA &lt;= a.COLA)。根据您的 SQL Server 版本,如果性能成为问题,您可以将其与 other options 进行比较。

【讨论】:

  • 蒂姆非常感谢。我需要能够通过 COLB DESC 订购。我试过这个... SELECT TOP(10) COLA, COLB, ROUND( -- 将运行总数相除... (SELECT CAST(SUM(COLB) AS FLOAT) FROM #MyTempTable WHERE COLB
  • 没关系...我明白了... SELECT TOP(10) COLA, COLB, ROUND( -- 将运行总数相除... (SELECT CAST(SUM(COLB) AS FLOAT) FROM #MyTempTable WHERE COLB >= a.COLB) / -- ...按全部总数 (SELECT CAST(SUM(COLB) AS FLOAT) FROM #MyTempTable), 2 ) AS COLC FROM #MyTempTable 作为 COLB DESC 的订单
【解决方案2】:

如果你不使用OLAP函数,那么你就得在表上做一个奇怪的自连接:

SELECT a.ColA, a.ColB, SUM(b.ColB) AS ColX
  FROM #MyTempTable AS a
  JOIN #MyTempTable AS b
    ON a.ColA <= b.ColA
 GROUP BY a.ColA, a.ColB

这将为您提供原始累积 SUM。您绝对可以将其用作子查询来获得答案,注意要获得百分比,您需要将累积总和除以总和:

SELECT ColA, ColB, ColX / (SELECT SUM(ColB) FROM MyTempTable) AS ColC
  FROM (SELECT a.ColA, a.ColB, SUM(b.ColB) AS ColX
          FROM #MyTempTable AS a
          JOIN #MyTempTable AS b
            ON a.ColA <= b.ColA
         GROUP BY a.ColA, a.ColB
       ) AS X
 ORDER BY ColA

你可以只写:

SELECT a.ColA, a.ColB, SUM(b.ColB) / (SELECT SUM(ColB) FROM MyTempTable) AS ColC
  FROM #MyTempTable AS a
  JOIN #MyTempTable AS b
    ON a.ColA <= b.ColA
 GROUP BY a.ColA, a.ColB
 ORDER BY a.ColA

将 ColC 表达式乘以 100 得到百分比而不是分数。

在 Mac OS X 10.7.3 上针对 IBM Informix 11.70.FC2 进行了测试,这两个查询都具有除法工作,产生了相同的答案(我注意到我得到的是 0.81 而不是问题中要求的 0.71):

Name1    218    0.34603174603174603174603174603175
Name2    157    0.5952380952380952380952380952381
Name3    134    0.80793650793650793650793650793651
Name4    121    1.0 

您可能必须使用 CAST 来确保使用浮点数而不是整数算术来完成除法 — 正如您所看到的,这对于 Informix 不是必需的(无论如何,SUM 都是浮点十进制数,以防万一表中有数十亿行,而不仅仅是其中的 4 行)。我可以使用ROUND(xxxx, 2) 改进演示文稿,只保留2 个小数位;强制转换为 DECIMAL(6,2) 将获得相同的结果,但应该由客户端负责呈现,而不是 DBMS。

【讨论】:

    【解决方案3】:

    在 MS SQL Server 中,这样做(ups,错误的子聚合 -> 错误的结果):

    create table #MyTempTable (cola varchar(10), colb int)
    
    insert into #MyTempTable(cola,colb)
    select 'Name1',218
    union all
    select 'Name2',157
    union all
    select 'Name3',134
    union all
    select 'Name4',121
    
    SELECT otab.COLA, otab.COLB,
           cast(otab.COLB as float)/(select SUM(cast(itab.colb as float))
                                     from #MyTempTable itab where itab.cola >= otab.cola) 
      from #MyTempTable otab
    
    drop table #MyTempTable
    

    【讨论】:

    • 我尝试将 CAST(COLB/(SELECT SUM(COLB) FROM #MyTempTable) AS DECIMAL(3,2)) 转换为 Pct_Total。我看到我只需要派发股息。谢谢!
    • 欢迎来到 Stack Overflow。使用 MarkDown 系统来提供答案需要一些时间来适应。为了使代码布局合理,缩进四个空格。编辑时,如果前(三)列中有字符,编辑框上方的图标 {} 会将突出显示的材料缩进四个空格 - 如果没有任何字符,它也会取消缩进第一列。有可用的帮助按钮。 (很快就掌握了这一切。)
    猜你喜欢
    • 2018-04-20
    • 1970-01-01
    • 2017-03-06
    • 2018-09-24
    • 1970-01-01
    • 1970-01-01
    • 2019-01-09
    • 2014-01-24
    相关资源
    最近更新 更多