postgresql 如何使用case语句根据同一列中的非空单元格更新空单元格?

ruyhziif  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(1)|浏览(137)

我是SQL新手,我试图在网上搜索类似的帖子,但一无所获。那就这样吧
我有一个表t1,它用以下列整理调查响应:dateidgrouplevel。还有更多的列,但这些基本上是我关心的。前3列告诉我谁回答了调查以及何时回答(idgroup列值之间存在多对多关系)。每个id-group组合在每个月最多有1个条目(日期值与该月的第一天挂钩)。level列是他们对调查的回应。
对于现有的每对idgroup,我想获得2022年和2023年每个月的level。问题是,我在那一栏里有很多空白。举个小例子:
日期|id|群|水准仪
2022-01-01 2022-01-01| 1|一个|零
2022-02-01 2022 -02-01| 1|一个|3
2022-03-01 2022-03-01| 1|一个|零
2022-04-01 2022-04-01| 1|一个|零
2022-05-01 2022-05-01| 1|一个|4
2022-06-01 2022-06-01| 1|一个|5个
2022-07-01 2022-07-01| 1|一个|零
所以,我想推断一下我现有的数据。对于level为空的每一行,我希望分配在“缺失”月份之前的最近非空月份的level。如果具有空值的行没有具有非空值的前一个月(即它是2022年1月),获取最早月份的值,其中非空level出现在空行之后。因此,期望的输出将是:
日期|id|群|水准仪
2022-01-01 2022-01-01| 1|一个|3
2022-02-01 2022 -02-01| 1|一个|3
2022-03-01 2022-03-01| 1|一个|3
2022-04-01 2022-04-01| 1|一个|3
2022-05-01 2022-05-01| 1|一个|4
2022-06-01 2022-06-01| 1|一个|5个
2022-07-01 2022-07-01| 1|一个|5个
我的方法是这样的:我使用了一个表t2来获取t1中具有非空level值的所有行。然后,我创建了CTE t3,基本上是t1的副本,多了一个名为insert的列。这个新列将是我放置外推的t1.level值的地方,我将使用一个简单的更新函数将t3.insert传输到相应的空t1.level行。

with t3 as 
    Select distinct t1.date, t1.id, t1.group, t1.level,
    Case
--for when the null t1 record is earlier than the earliest t2 record
        When (t2.date = (select min(t2.date) where (t1.id, t1.group) = (t2.id, t2.group)))
        Then t2.level
--when the null t1 record is later than some existing t2 record
        When (t2.date = (select max(t2.date) where (t1.id, t1.group) = (t2.id, t2.group) AND t2.date <= t1.date))
        Then t2.level
        Else null
    End as "insert"
    from t1
    Join t2 on (t1.id, t1.group) = (t2.id, t2.group)
    GROUP BY t1.date, t1.id, t1.group, t1.level, t2.id, t2.group, t2.date, t2.level
    ORDER BY t1.id, t1.group, t1.date
)

我甚至无法进入更新t1.level的部分,因为我遇到了问题。我发现对于每一对idgroupt3将每个t2.level值分配给每个t3.insert。对于2022年1月id = 1和group = A的记录:
日期|id|群|水准仪|插入
2022-01-01 2022-01-01| 1|一个|零|3
2022-01-01 2022-01-01| 1|一个|零|4
2022-01-01 2022-01-01| 1|一个|零|5个
似乎postgresql忽略了case语句中的min()函数。我可能犯了一个很低级的错误。

oxcyiej7

oxcyiej71#

下面的查询演示了一种确定NULL调查级别的替代值的方法,方法是查找前一个非NULL级别,如果不存在,则查找下一个非NULL级别。

WITH t1(survey_date, id, survey_group, survey_level) AS (
  VALUES ('2022-01-01'::date, 1, 'A', null),
         ('2022-02-01'::date, 1, 'A', 3),
         ('2022-03-01'::date, 1, 'A', null),
         ('2022-04-01'::date, 1, 'A', null),
         ('2022-05-01'::date, 1, 'A', 4),
         ('2022-06-01'::date, 1, 'A', 5),
         ('2022-07-01'::date, 1, 'A', null)
)
SELECT t1.survey_date, t1.id, t1.survey_group, t1.survey_level,
       COALESCE(t1.survey_level,
                -- prior non-NULL level
                (array_agg(t1.survey_level)
                   FILTER (WHERE t1.survey_level IS NOT NULL)
                   OVER (PARTITION BY t1.id, t1.survey_group
                         ORDER BY t1.survey_date DESC
                         ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING))[1],
                -- next non-NULL level
                (array_agg(t1.survey_level)
                   FILTER (WHERE t1.survey_level IS NOT NULL)
                   OVER (PARTITION BY t1.id, t1.survey_group
                         ORDER BY t1.survey_date
                         ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING))[1]) AS substitute_level
  FROM t1
  ORDER BY t1.survey_date, t1.id, t1.survey_group;

前一个值和下一个值被收集到数组中,数组的第一个元素是给定方向上最近的非NULL值。因为先前的值是按降序排序的,所以使用FOLLOWING而不是PRECEDING来定义窗口框架。

相关问题