使用 MySQL 或 H2 将空值替换为列中的最新值

Replace null values with the latest value in a column using MySQL or H2

提出了同样的问题,但是所提供的所有答案都是针对 SQL 服务器 2008 的,并且这些方法都不适用于 MySQL 或 H2:

replace NULL values with latest non-NULL value in resultset series (SQL Server 2008 R2)

类似问题(还有 SQL 服务器 2008,我们不知道所有表)

Replace null value by latest value

我需要的是可以与 MySQL 或 H2

一起使用的东西

所以如果我们有

product timestamp          price 
------- ----------------   -----
   5678 2008-01-01         12.34
   5678 2008-01-02         NULL
   5678 2008-01-03         NULL
   5678 2008-01-03         23.45
   5678 2008-01-04         NULL

结果应该是

product timestamp          price 
------- ----------------   -----
   5678 2008-01-01         12.34
   5678 2008-01-02         12.34
   5678 2008-01-03         12.34
   5678 2008-01-03         23.45
   5678 2008-01-04         23.45

MySQL代码:

CREATE TABLE `table1` (
  `product` int(11) NOT NULL,
  `timestamp` date NOT NULL,
  `price` decimal(10,0) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;



INSERT INTO `table1` (`product`, `timestamp`, `price`) VALUES
(5678, '2008-01-01', '12'),
(5678, '2008-01-02', NULL),
(5678, '2008-01-03', NULL),
(5678, '2008-01-03', '23'),
(5678, '2008-01-04', NULL);

请保持简单。

如果你有 mysql 6.x 你可以使用用户定义的变量

CREATE TABLE table1 (
  `product` INTEGER,
  `timestamp` DATETIME,
  `price` VARCHAR(5)
);

INSERT INTO table1
  (`product`, `timestamp`, `price`)
VALUES
  ('5678', '2008-01-01 12:00', '12.34'),
  ('5678', '2008-01-01 12:01', NULL),
  ('5678', '2008-01-01 12:02', NULL),
  ('5678', '2008-01-01 12:03', '23.45'),
  ('5678', '2008-01-01 12:04', NULL);
SELECT 
`product`
, `timestamp`
, @price := IF(`price` IS NULL, @price,`price`) 'price'
FROM (SELECT * FROM table1 ORDER BY `timestamp`) t1,(SELECT @price := 0) t2
product | timestamp           | price
------: | :------------------ | :----
   5678 | 2008-01-01 12:00:00 | 12.34
   5678 | 2008-01-01 12:01:00 | 12.34
   5678 | 2008-01-01 12:02:00 | 12.34
   5678 | 2008-01-01 12:03:00 | 23.45
   5678 | 2008-01-01 12:04:00 | 23.45

db<>fiddle here

我理解这个问题是为了更新 table 数据,一个产品的价格不应该影响另一个产品的价格。看起来像这样:

set @price:=null, @product:=null;
update table1
    set price=if(price is not null,
        @price:=price,
        if(product=@product,@price,price)
    ),
    product=@product:=product
order by product, timestamp;

如果目标只是在 select 期间用之前的值替换空值,这可以使用 window 函数轻松实现,除了 mysql 和 mariadb 还没有实施了 LAG() IGNORE NULLS 函数 :( 因此它需要使用变量(参见 nbk 的回答)或 self-join:

select t.product, t.timestamp, coalesce(t.price, substr(max(concat(t2.timestamp,t2.price)),length(t.timestamp)+1)) price
from table1 t
left join table1 t2 on t2.product=t.product and t2.timestamp < t.timestamp and t.price is null and t2.price is not null
group by t.product, t.timestamp, t.price;

分组依据是必需的,但会删除重复的条目;按主键分组会更好。