Postgresql填充间隙 - 给定分支的最新可用信息矩阵

时间:2015-04-14 14:36:15

标签: sql postgresql window-functions gaps-in-data

我有一个包含导入文件索引的表,其中包含每个导入文件的日期和分支。

现在我需要对多个分支进行合并,因此,当我们有假期时,我必须复制来自某些分支的信息,以便数据保持一致,基本上我需要用最新的可用信息填补这些空白

我尝试使用排名进行一些自我加入,以便在它们之间切换并获取以前的数据,但它不起作用。

我所拥有的是一张桌子:

rundate, branch, imported 
2015-04-01, PL1, TRUE 
2015-04-01, ES1, TRUE 
2015-04-01, CZ4, TRUE 
2015-04-02, PL1, TRUE 
2015-04-02, ES1, TRUE 
2015-04-02, CZ4, TRUE   
2015-04-03, ES1, TRUE 
2015-04-03, CZ4, TRUE

在这个例子中,我想做一个返回的查询:

gap_date, branch, real_date
2015-04-03, PL1, 2015-04-02

此表非常小(几千行),因此,性能不应该是一个大问题。

关于如何实现这一点的任何想法?

现在我使用的函数接收间隙日期的rundate和branch作为参数,并在作为参数传递的日期之前回答最新的函数(使用max(rundate),其中rundate< ='$ 1')

谢谢!

3 个答案:

答案 0 :(得分:1)

您可以使用outer joinsubquerycross join

架构:

create table tbl(rundate date, 
                 branch varchar(10), 
                 imported bool);
insert into tbl values('2015-04-01', 'PL1', TRUE),
('2015-04-01', 'ES1', TRUE), 
('2015-04-01', 'CZ4', TRUE), 
('2015-04-02', 'PL1', TRUE), 
('2015-04-02', 'ES1', TRUE), 
('2015-04-02', 'CZ4', TRUE),  
('2015-04-03', 'ES1', TRUE), 
('2015-04-03', 'CZ4', TRUE); 

查询:

select q.rundate as gap_date,q.branch,
       (select max(tt.rundate) 
        from tbl tt
        where tt.rundate<q.rundate and tt.branch=q.branch)
        as real_date
from tbl t
right outer join(
         select rundate,branch from (
                select distinct rundate from tbl) t1
                cross join (
                select distinct branch from tbl)t2
          )q 
on t.rundate=q.rundate and t.branch=q.branch
where t.branch is null

结果:

gap_date    branch  real_date
2015-04-03  PL1     2015-04-02

答案 1 :(得分:0)

你必须在一组中选择所有独特的日期,在另一组中选择所有独特的分支 - 制作它的笛卡尔产品 - 然后你可以检查你有差距的组合......这就是我的意思:

CREATE TEMPORARY TABLE _matrix
SELECT
t1.rundate,
t2.branch
(SELECT DISTINCT rundate FROM yourtable) t1,
(SELECT DISTINCT branch FROM yourtable) t2

然后你可以使用LEFT JOIN和“WHERE ... IS NULL”语句找到空白:

SELECT
m.rundate,
m.branch
FROM _matrix m
LEFT JOIN yourtable yt ON(yt.rundate = m.rundate AND yt.branch = m.branch)
WHERE yt.rundate IS NULL

当然,没有临时表也可以实现同样的效果 - 只使用子查询。特别是当表演并不重要时。

答案 2 :(得分:0)

这是来自@voycheck carthesian product of both domains解决方案,除了实际存在的记录。

WITH br AS (
        SELECT DISTINCT branch AS branch FROM tbl
        )
, mima AS (
        SELECT MIN(rundate) as mi
             , MAX(rundate) as ma
        FROM tbl)
, rng AS (
        SELECT generate_series( mima.mi, mima.ma, '1 day'::interval)::date AS rundate
        FROM mima
        )
SELECT * FROM rng
JOIN br ON NOT EXISTS ( -- cartesian product EXCEPT
        SELECT *
        FROM tbl t
        WHERE t.branch = br.branch
        AND t.rundate = rng.rundate
        )
        ;