SQL如何检查null之前的值是否与null之后的窗口函数相同

时间:2019-02-23 21:17:23

标签: sql

我有一个带有x列的表,该列具有许多类似这样的rendom值:

7
null
null
4
null
null
null
4

我需要检查NULL之前的数字是否与NULL之后的数字相同,如果是,请将NULL转换为该数字。如果不是,则NULL保留。因此,结果将是另一列具有以下值的列:

7
null
null
4
4
4
4
4

有人可以帮助我吗?

2 个答案:

答案 0 :(得分:0)

使用窗口函数:

WITH cte AS (
  SELECT t.*, SUM(CASE WHEN val IS NULL THEN 0 ELSE 1 END) OVER(ORDER BY id) AS grp
  FROM t
)
SELECT c1.id, c1.val,
      CASE WHEN c2.val = MIN(c1.val) OVER(PARTITION BY c1.grp)
          THEN c2.val
          ELSE c1.val
      END AS filled_val
FROM cte c1
LEFT JOIN cte c2
  ON c1.grp = c2.grp-1
  AND c2.val IS NOT NULL;

db<>fiddle demo

答案 1 :(得分:0)

此答案假设您有一个用于对值进行排序的唯一列,称为id(没有这样的列,您的问题就无法解决)。

如果使用的RDBMS在窗口功能(例如Oracle)中支持选项IGNORE NULLS,则可以按以下步骤进行操作:

SELECT id, CASE WHEN val IS NULL AND lg = ld THEN lg ELSE val END val
FROM (
    SELECT 
        id,
        val,
        LAG(val IGNORE NULLS) OVER(ORDER BY id) lg,
        LEAD(val IGNORE NULLS) OVER(ORDER BY id) ld
     FROM t
) x

Demo on DB Fiddle

ID |  VAL
-: | ---:
 1 |    7
 2 | null
 3 | null
 4 |    4
 5 |    4
 6 |    4
 7 |    4
 8 |    4

在不支持窗口函数的RDBMS(例如MySQL <8.0)上,您可以采用效率不高但安全的选项,即使用JOIN和相关子查询来查找值的前一个和下一个记录不为空:

SELECT t1.id, CASE WHEN t0.val = t2.val THEN t0.val ELSE t1.val END val
FROM t t1
LEFT JOIN t t0
    ON  t1.val IS NULL 
    AND t0.val IS NOT NULL
    AND t0.id < t1.id 
    AND NOT EXISTS (SELECT 1 FROM t WHERE val IS NOT NULL AND id < t1.id AND id > t0.id)
LEFT JOIN t t2
    ON  t1.val IS NULL 
    AND t2.val IS NOT NULL
    AND t2.id > t1.id 
    AND NOT EXISTS (SELECT 1 FROM t WHERE val IS NOT NULL AND id > t1.id AND id < t2.id)

Demo on DB Fiddle