根据多个先前行的条件更新特定行中的表

时间:2014-02-26 13:42:48

标签: sql postgresql

我的数据集包括每天(实际上是工作日,但对于答案来说无关紧要)不同公司的时间序列,我使用PostgreSQL。我的数据集中有一个指标变量,取值为1,-1,大多数时间为0.为了更好的问题可读性,我指的是指标变量不等于零作为指标天数的日子。

因此,对于前三天同一公司的另一个指标日之前的所有指标日,指标变量应更新为零。

我们可以使用以下示例数据集:

day            company   indicator
2012-01-04     A         0
2012-01-04     B         0
2012-01-05     A         0
2012-01-05     B         -1
2012-01-06     A         0
2012-01-06     B         0
2012-01-09     A         0
2012-01-09     B         0
2012-01-10     A         0
2012-01-10     B         1
2012-01-11     A         1
2012-01-11     B         1
2012-01-12     A         0
2012-01-12     B         0
2012-01-13     A         1
2012-01-13     B         1

因此,必须更新为零的指标值为:2012-01-10公司B的条目,2012-01-11公司B的条目和2012-01-13两个条目,因为所有这些都是在3个工作日内同一公司的另一个指标日之前。

我尝试了以下

    UPDATE test SET indicator = 0 
    WHERE day IN (
    SELECT day
      FROM (
           SELECT company, day, 
           COUNT(CASE WHEN indicator <> 0 THEN 1 END) 
              OVER (PARTITION BY company ORDER BY day 
                    ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) As cnt
           FROM test
           ) alias
      WHERE cnt >= 2)

这个想法是计算指标变量在当天和前3天不等于零的日子。如果计数超过1,则将指标值更新为零。不幸的是,它无法区分公司。因此,它在示例数据中的作用是在2012-01-11,它还将公司A的条目更新为零,因为在B的指示日前一天。

也许我需要像“按公司划分”这样的更新,但它不存在。

您有任何想法如何修复它,或者如何用另一种方法解决我的问题?

1 个答案:

答案 0 :(得分:1)

Postgresql允许您为IN语句使用多个列,因此我认为您只需将查询更改为:

UPDATE test SET indicator = 0 
WHERE (day, company) IN (
SELECT day, company
    FROM (
        SELECT company, day, 
        COUNT(CASE WHEN indicator <> 0 THEN 1 END) 
            OVER (PARTITION BY company ORDER BY day 
                ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) As cnt
        FROM test
        ) alias
    WHERE cnt >= 2)

获得您需要的结果。

<强> Example on SQL Fiddle