在多级时间序列数据中插入缺失的日期记录

时间:2018-11-13 16:28:36

标签: mysql

背景 我的数据相当简单。多个客户,每个客户可以有多个帐户,每个帐户可以包含多个产品(客户)。我在每个工作日都捕获了这些数据,这意味着没有周末或任何公共假期的记录。

 Client    Account   Product        Total_value     Date
 10        36        '29764T101'    3240            '2018-10-01' 
 10        35        'TRZ300'       29761.93        '2018-10-02' 
 10        36        '29764T101'    3720            '2018-10-02' 
 10        35        'TRZ300'       29761.93        '2018-10-03' 
 10        36        '29764T101'    3240            '2018-10-03' 
 10        35        'TRZ300'       30282.76        '2018-10-04' 
 10        36        '29764T101'    3300            '2018-10-04' 
 10        35        'TRZ300'       30282.76        '2018-10-05' 
 10        36        '29764T101'    3300            '2018-10-05' 
 10        35        'TRZ300'       30282.76        '2018-10-08' 
 10        36        '29764T101'    3300            '2018-10-08' 
 10        35        'TRZ300'       30282.76        '2018-10-09' 
 10        36        '29764T101'    3060            '2018-10-09' 

问题陈述 我需要一种在每月时间序列数据中插入缺少日期的记录的方法。丢失的数据来自最后一个可用数据行。因此星期五的记录将在星期六和星期日重复出现。如果星期三不起作用,则将在星期二填充星期二的记录,依此类推。

在以上数据中,没有10月6日和10月7日的数据。由于此客户(10)有两个帐户(35、36),并且每个帐户只有一个产品(35->'TRZ300'和36->'29764T101'),因此,我需要一种方法来插入两个第六条记录(这两个记录分别在5日)和相同的内容在6日重复。

请注意,我的数据处于客户/帐户/产品/日期级别,因此需要查找和复制此组合。上面的示例数据仅适用于一个客户端。实际数据有多个客户,有多个帐户,每个帐户可以有多个产品(客户)。

预期产量

 Client    Account   Product        Total_value     Date
 10        36        '29764T101'    3240            '2018-10-01' 
 10        35        'TRZ300'       29761.93        '2018-10-02' 
 10        36        '29764T101'    3720            '2018-10-02' 
 10        35        'TRZ300'       29761.93        '2018-10-03' 
 10        36        '29764T101'    3240            '2018-10-03' 
 10        35        'TRZ300'       30282.76        '2018-10-04' 
 10        36        '29764T101'    3300            '2018-10-04' 
 10        35        'TRZ300'       30282.76        '2018-10-05' 
 10        36        '29764T101'    3300            '2018-10-05'

 ------------------------ Inserted Records --------------------- 
 10        35        'TRZ300'       30282.76        '2018-10-06' 
 10        36        '29764T101'    3300            '2018-10-06' 
 10        35        'TRZ300'       30282.76        '2018-10-07' 
 10        36        '29764T101'    3300            '2018-10-07' 
 ------------------------ Inserted Records ---------------------

 10        35        'TRZ300'       30282.76        '2018-10-08' 
 10        36        '29764T101'    3300            '2018-10-08' 
 10        35        'TRZ300'       30282.76        '2018-10-09' 
 10        36        '29764T101'    3060            '2018-10-09' 

到目前为止已尝试 我知道一种方法可能是创建日历表,然后进行左联接。

尝试1 通过创建日历表,然后使用以下查询,我得到了解决方案:

SELECT  
CASE WHEN ID IS NULL THEN (SELECT ID 
                        FROM T tt 
                        WHERE tt.Date < t1.minDt
                        ORDER BY tt.Date DESC
                        LIMIT 1)  
ELSE ID END ID,
CASE WHEN Name IS NULL THEN (SELECT Name 
                        FROM T tt 
                        WHERE tt.Date < t1.minDt
                        ORDER BY tt.Date DESC
                        LIMIT 1) 
ELSE Name END Name,
CASE WHEN SomeVal IS NULL THEN (SELECT SomeVal 
                        FROM T tt 
                        WHERE tt.Date < t1.minDt
                        ORDER BY tt.Date DESC
                        LIMIT 1) 
ELSE SomeVal END SomeVal,
CASE WHEN OtherVal IS NULL THEN (SELECT OtherVal 
                        FROM T tt 
                        WHERE tt.Date < t1.minDt
                        ORDER BY tt.Date DESC
                        LIMIT 1) 
ELSE OtherVal END OtherVal,
minDt
FROM calendar t1 
LEFT JOIN T t2 ON t1.minDt = t2.Date
ORDER BY t1.minDT;

当ID值恒定时,此解决方案有效。我意识到我的数据集有成千上万条具有数百个唯一ID值的记录。每个ID可能缺少值。上面的查询仅替换数据的顶部,而不替换整个数据。我需要为每个ID运行相同的查询。我猜按分区可以在mysql中工作,但是我不太确定如何尝试。

尝试2 这是@Nick的建议。我没有完全遵循它,但是它只对我的虚拟数据起作用,但是只是在一个级别上。我不太确定如何将这种解决方案扩展到多层次数据,就像我上面所说的那样。

SELECT thedate,
       @name := coalesce(Name, @name) AS Name,
       @someval := coalesce(SomeVal, @someval) AS SomeVal,
       @otherval := coalesce(OtherVal, @otherval) AS OtherVal,
       @id := id AS id
FROM (SELECT c.thedate, i.id, t.Name, t.SomeVal, t.OtherVal
      FROM calendar c
      JOIN (SELECT DISTINCT id FROM t) i
      LEFT JOIN t ON t.date = c.thedate AND t.id = i.id) g
CROSS JOIN (SELECT @id := 0, @name := '', @someval := 0, @otherval := 0) v
ORDER BY id, thedate

DB小提琴样本数据 我已经创建了一个虚拟数据,任何人都可以在https://www.db-fiddle.com/f/wzg4mYtbdTeJGrGHfqJ75k/1

示例数据和日历数据。

0 个答案:

没有答案