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