【问题标题】:SQL : Summing the values in a column till first non zero values appears in other column?SQL:对列中的值求和,直到第一个非零值出现在其他列中?
【发布时间】:2022-01-31 11:56:52
【问题描述】:

假设,我有一个看起来像 t1 的表

id value1 value2 wk_id
1 2 0 1
1 1 1 2
1 3 0 3
2 2 1 2
2 2 0 3
3 1 0 2
3 2 0 4
3 3 0 5

我想总结 value1 直到 value2 第一次出现非零值。 最终产品必须如下所示:

id value1
1 2
2 0
3 6

如何在 SQL 中执行此操作?

【问题讨论】:

  • 问题是表数据是一个无序的数据集。您有确定顺序的列吗?日期时间列可能吗?那么,为什么要标记两个不同的 DBMS?您使用的是 MySQL 还是 PostgreSQL?
  • @ThorstenKettner 是的,数据集有一个日期时间列。更新数据集

标签: mysql sql


【解决方案1】:

如果您的 MySQL 版本支持窗口函数,您可以尝试使用 SUM 窗口函数和条件聚合函数作为标志来表示您的逻辑(直到第一次出现在 value2 上的非零值)

然后再做条件聚合函数。

查询 #1

SELECT id,
       SUM(CASE WHEN flag = 0 THEN value1 ELSE 0 END) value1
FROM (
  SELECT *,
         SUM(CASE WHEN value2 = 1 THEN -1 ELSE 0 END) OVER(PARTITION BY ID ORDER BY wk_id) flag
  FROM T 
) t1
GROUP BY id;
id value1
1 2
2 0
3 6

View on DB Fiddle

【讨论】:

  • 感谢您的解决方案。但是,当我们对分区求和时,为什么最初 value2 为零的条目的标志不是 -1。如果有任何非零 value2 ,则 id 的所有行不应该为 -1 吗?为什么它的行为像滚动总和?
【解决方案2】:
WITH cte AS (
    SELECT *,
           CASE WHEN SUM(value2) OVER (partition by id ORDER BY wk_id) = 0
                THEN SUM(value1) OVER (partition by id ORDER BY wk_id) 
                ELSE 0
                END sum_value1
    FROM test
    ORDER BY id, wk_id
)
SELECT id, MAX(sum_value1) sum_value1
FROM cte
GROUP BY id;

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=0fcdca008e4a821f952de4d608434bcf

【讨论】:

    【解决方案3】:

    一个选项是NOT EXISTS 子句,寻找停止行(value2 = 1 的第一行)。

    select id, sum(value1)
    from mytable
    where not exists
    (
      select null
      from mytable stoprow
      where stoprow.id = mytable.id
      and stoprow.wk_id <= mytable.wk_id
      and stoprow.value2 = 1
    )
    group by id
    order by id;
    

    【讨论】:

      【解决方案4】:

      也可以通过自联接来完成计算出的滚动总计 value2。

      select id
      , sum(if(roll_tot_value2=0,value1,0)) as total
      from 
      (
        select t1a.id, t1a.wk_id, t1a.value1
        , sum(t1b.value2) as roll_tot_value2
        from t1 as t1a
        join t1 as t1b
          on t1b.id = t1a.id
         and t1b.wk_id <= t1a.wk_id
        group by t1a.id, t1a.wk_id, t1a.value1
      ) q
      group by id;
      
      id total
      1 2
      2 0
      3 6

      测试 dbfiddle here

      【讨论】:

        【解决方案5】:

        您可以使用子查询:

        select t.id, coalesce(
           (select sum(t2.value1) from t1 t2 where t2.value2 = 0 and t2.id = t.id 
               and (not exists (select 1 from t1 t3 where t3.value2 = 1 and t3.id = t.id) 
               or t2.wk_id < (select min(t4.wk_id) from t1 t4 where t4.id = t.id and t4.value2 = 1))), 0) 
        from t1 t group by t.id
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-28
          相关资源
          最近更新 更多