【问题标题】:Transform SQL Server table based on calculation根据计算转换 SQL Server 表
【发布时间】:2021-12-31 05:26:53
【问题描述】:

我有一张像下面这样的表格

Column1 Column2
A 200
A 200
A 0
B 300
B 200
C 100

我想把这张表变成下表

带计算:对于column1的每个元素,SUM(column2)/count of (non-zero column2)

Column1 Column2
A ((200+ 200 + 0) / 2) = 200
B ((300 + 200) / 2) = 250
C 100 / 1 = 100

我唯一能想到的就是循环遍历Column1 的不同元素并运行:

SELECT SUM(Column2) 
FROM Table 
WHERE Column1 = i / (SELECT COUNT(Column2) 
                     FROM Table 
                     WHERE Column1 = i AND Column2 <> 0)

并生成一个表格。

有更好的方法吗?

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    使用聚合:

    SELECT Column1,
           SUM(Column2) / COUNT(CASE WHEN Column2 <> 0 THEN 1 END) AS Column2
    FROM yourTable
    GROUP BY Column1
    HAVING COUNT(CASE WHEN Column2 <> 0 THEN 1 END) > 0;
    

    【讨论】:

    • 如果任何 column1 值的所有 olumn2 都是 0,那么它将失败并出现错误“遇到除以零错误。”。
    • 我的回答是有效的,假设 OP 期望每个组总是至少有一个非零值。如果没有,OP 将不得不澄清预期的行为。
    • 整洁。 COUNT(NULLIF(Column2, 0)) 更短一些,如果更模糊一些。 @KaziMohammadAliNur 是对的(在他自己的回答中),您也可以删除 WHERE 中的那些行,因为它不会影响最终结果。如:(x + 0) / 1x / 1 相同
    【解决方案2】:

    您可以使用 where 子句删除 column2 中包含 0 的行,然后使用聚合来获得您想要的结果。但它会删除所有 column1 中所有 columnd2 中为 0 的那些 column1 值。

    但是 Query2 将返回 column2 中值为零的行,而不是删除删除的行。

    架构和插入语句:

     create table testTable (Column1    varchar(50), Column2 int);
     insert into testTable values('A',  200);
     insert into testTable values('A',  200);
     insert into testTable values('A',  0);
     insert into testTable values('B',  300);
     insert into testTable values('B',  200);
     insert into testTable values('C',  100);
     insert into testTable values('D',  0);
    

    查询1:

     SELECT Column1,
            SUM(Column2) / COUNT(*) AS Column2
     FROM testTable where column2<>0
     GROUP BY Column1;
    

    输出:

    Column1 Column2
    A 200
    B 250
    C 100

    查询2:

     SELECT Column1,
            Coalesce(SUM(Column2) / nullif(COUNT(CASE WHEN Column2 <> 0 THEN 1 END),0),0) AS Column2
     FROM testTable
     GROUP BY Column1;
    

    输出:

    Column1 Column2
    A 200
    B 250
    C 100
    D 0

    db小提琴here

    【讨论】:

    • 0 / 0 不是0,它被定义为Not A Number,您可以将其表示为NULL。所以我会删除最后的COALESCE
    • 你是绝对正确的。我认为而不是 NULL OP 会更喜欢结果中的 0。
    【解决方案3】:

    您可以使用派生表过滤掉 0 column2 行。然后,您可以应用 GROUP BY。

    declare @table table (Column1 char(1),  Column2 int)
    insert into @table values
    ('A',200),
    ('A',200),
    ('A',0  ),
    ('B',300),
    ('B',200),
    ('C',100);
    
    SELECT Column1, (sum(column2) / count(column2) ) as column2
    from
    (
    SELECT * FROM @TABLE where Column2 <> 0) as t
    group by Column1
    
    Column1 column2
    A 200
    B 250
    C 100

    【讨论】:

      【解决方案4】:

      在除以 column2 的总和时,检索 column1 的不同值并忽略 column2 的零值。并且还要考虑这里除以零错误。

      -- SQL Server
      SELECT t.column1
           , t.column2 / (CASE WHEN (t.total - t.total_zero) = 0 THEN 1 ELSE (t.total - t.total_zero) END)
      FROM (SELECT column1
                 , SUM(column2) column2
                 , COUNT(CASE WHEN column2 = 0 THEN 1 END) total_zero
                 , COUNT(1) total
            FROM test
            GROUP BY column1) t
      

      请查看此网址https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=3853456941909ffffb8792415adc1f6f

      【讨论】:

        【解决方案5】:

        使用AVG() 窗口函数,因为您想要Column2 的平均值。

        如果您希望结果中包含Column1 的所有值,即使它们在Column2 中只有0s:

        SELECT DISTINCT Column1,
               AVG(CASE WHEN Column2 <> 0 THEN Column2 END) OVER (PARTITION BY Column1) Column2
        FROM tablename;
        

        如果您想要 Column1 的值至少有 1 个 Column2 而不是 0 的结果:

        SELECT DISTINCT Column1,
               AVG(Column2) OVER (PARTITION BY Column1) Column2
        FROM tablename
        WHERE Column2 <> 0;
        

        请参阅demo

        请注意,SQL Server 会将整数的平均值截断为整数,因此如果您希望将结果作为浮点数,您应该将 Column2 乘以 1.0,例如:

        AVG(CASE WHEN Column2 <> 0 THEN 1.0 * Column2 END) 
        

        或:

        AVG(1.0 * Column2)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-05-29
          • 1970-01-01
          • 1970-01-01
          • 2018-10-06
          • 2019-02-05
          • 1970-01-01
          • 2017-03-07
          • 1970-01-01
          相关资源
          最近更新 更多