如何在一定的价值差距之前确定每组的行? 基本SELECT 您的UPDATE

问题描述

我想根据Postgresql中相邻行之间另一个列值的差异来更新表中的特定列。

这是一个测试设置:

CREATE TABLE test(
   main INTEGER,sub_id INTEGER,value_t INTEGER);

INSERT INTO test (main,sub_id,value_t)
VALUES
    (1,1,8),(1,2,7),3,3),4,85),5,40),(2,1),41);

我的目标是从main开始的每个组sub_id 1中,通过按以下顺序检查升序来确定diff中的哪个值超过某个阈值(例如 -10) sub_id。在达到阈值之前,我要标记每个传递的行 AND 方法是在列FALSE中填充一个值,例如newval1

enter image description here

我应该使用循环还是有更智能的解决方案?

代码中的任务描述:

FOR i in GROUP [PARTITION BY main ORDER BY sub_id]:
    DO until diff > 10 OR diff <-10
        SET newval = 1 AND LEAD(newval) = 1

解决方法

您的问题很难理解,“ value_t”列与该问题无关,您忘记了在SQL中定义“ diff”列。

无论如何,这是您的解决方案:

WITH data AS (
  SELECT main,sub_id,value_t,abs(value_t
             - lead(value_t) OVER (PARTITION BY main ORDER BY sub_id)) > 10 is_evil
  FROM test
)
SELECT main,CASE max(is_evil::int)
            OVER (PARTITION BY main ORDER BY sub_id
                  ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
       WHEN 1 THEN NULL ELSE 1 END newval
FROM data;

我正在使用CTE准备数据(计算一行是否为“ evil”),然后使用“ max”窗口函数检查当前行之前是否存在任何“ evil”行。分区。

,

基本SELECT

尽快:

SELECT *,bool_and(diff BETWEEN -10 AND 10) OVER (PARTITION BY main ORDER BY sub_id) AS flag
FROM (
   SELECT *,value_t - lag(value_t,1,value_t) OVER (PARTITION BY main ORDER BY sub_id) AS diff
   FROM   test
   ) sub;
细点
  • 您的思想模型围绕窗口函数lead()演化。但是它的对应对象lag()的使用效率更高,因为在大间隙之前的行中没有逐个错误。 或者 ,将lead()使用倒序排列(ORDER BY sub_id DESC)。

  • 为避免在分区的第一行使用NULL,请默认提供value_t作为第3个参数,这将使diff 0而不是NULL。 lead()lag()都具有该功能。

  • diff BETWEEN -10 AND 10@diff < 11快一点(也更清晰,更灵活)。 (@ being the "absolute value" operator,等同于abs() function。)

  • 外窗函数中的
  • bool_or() or bool_and()对于将所有行标记到最大间隙可能是最便宜的。

您的UPDATE

在达到阈值之前,我想标记每个通过的行和条件为FALSE的一行,方法是在列newval中填充一个值,例如1

再次,尽快。

UPDATE test AS t
SET    newval = 1
FROM  (
   SELECT main,bool_and(diff BETWEEN -10 AND 10) OVER (PARTITION BY main ORDER BY sub_id) AS flag
   FROM (
      SELECT main,value_t) OVER (PARTITION BY main ORDER BY sub_id) AS diff
      FROM   test
      ) sub
   ) u
WHERE (t.main,t.sub_id) = (u.main,u.sub_id)
AND    u.flag;
细点
  • 计算单个查询中的所有值通常比关联子查询要快得多。

  • 添加的WHERE条件AND u.flag确保我们仅更新实际需要更新的行。
    如果某些行在newval中可能已经具有正确的值,请添加另一个子句以避免这些空更新:AND t.newval IS DISTINCT FROM 1 参见:

  • SET newval = 1分配一个常量(即使在这种情况下我们可以使用实际计算出的值),也便宜一些。

db 提琴here

,

在汇总子查询中存在:


UPDATE test u
SET value_t = NULL
WHERE EXISTS (
        SELECT * FROM (
                SELECT main,ABS(value_t - lag(value_t)
                       OVER (PARTITION BY main ORDER BY sub_id) ) AS absdiff
                FROM test
                ) x
        WHERE x.main = u.main
        AND x.sub_id <= u.sub_id
        AND x.absdiff >= 10
        )
        ;

SELECT * FROM test
ORDER BY main,sub_id;

结果:


UPDATE 3
 main | sub_id | value_t 
------+--------+---------
    1 |      1 |       8
    1 |      2 |       7
    1 |      3 |       3
    1 |      4 |        
    1 |      5 |        
    2 |      1 |       3
    2 |      2 |       1
    2 |      3 |       1
    2 |      4 |       8
    2 |      5 |        
(10 rows)