如何合并表并从上一个表创建新记录(如果缺少)?

时间:2019-08-09 15:31:26

标签: sql-server hiveql

我每个月都会得到一份用户列表及其家庭邮政编码。但是,并非每个用户都提供每个月的邮政编码,因此我的月度表大小永远都不会相同。

我要做的是创建一个主表,该表具有从第一个月开始的每个用户每个月的记录。然后,如果第一个月的用户没有出现在第二个月,则他们仍应获得第二个月的记录,并根据上个月分配邮政编码。

例如,我有两个看起来像这样的表:

UserNumber Month  ZIP
1          201701 12345
2          201701 30032
3          201701 01432
Etc.
UserNumber Month  ZIP
1          201702 12345
3          201702 01433
4          201702 30032
Etc.

您可以看到一些邮政编码会更改(用户3被“移动”),这没关系。但是用户2没有201702的记录。但是我的新主表应该为他们使用201701邮政编码的记录。因此,主表应如下所示:

UserNumber Month  ZIP
1          201701 12345
1          201702 12345
2          201701 30032
2          201702 30032 
3          201701 01432
Etc.

如上所述,用户2的201702记录使用与我们有记录相同的邮政编码。有时会丢失多个月份,所以我想获取比当前月份少的最新记录。

我曾尝试基于表相交创建多个临时表,然后将它们附加在一起,并且有效。但是,随着30个月以上的数据变得非常复杂和乏味,因此我希望有更好的方法。而且该主表也必须每个月进行更新。

任何建议,我将不胜感激!

当前数据位于S3中,我可以使用Hive进行访问,因此HiveQL解决方案将是理想选择,因此我不必将所有数据导入到SSMS中,但是如果使用SQL在SSMS中这样做更容易,我可以做到这一点也是

2 个答案:

答案 0 :(得分:1)

以下解决方案适合您的问题:

begin tran

create table #tbl1 (UserNumber int, [Month] int, ZIP char(5));
create table #tbl2 (UserNumber int, [Month] int, ZIP char(5));
create table #tbl3 (UserNumber int, [Month] int, ZIP char(5));

insert into #tbl1 (UserNumber, [Month], ZIP)
select 1, 201701, '12345' union all
select 2, 201701, '30032' union all
select 3, 201701, '01432';

insert into #tbl2 (UserNumber, [Month], ZIP)
select 1, 201702, '12345' union all
select 3, 201702, '01433' union all
select 4, 201702, '30032';

insert into #tbl3 (UserNumber, [Month], ZIP)
select 3, 201703, '01435' union all
select 4, 201703, '30032';

create table #full (UserNumber int, [Month] int, ZIP char(5));

insert into #full (UserNumber, [Month], ZIP)
select UserNumber, [Month], ZIP from #tbl1
union all
select UserNumber, [Month], ZIP from #tbl2
union all
select UserNumber, [Month], ZIP from #tbl3;

CREATE UNIQUE CLUSTERED INDEX [CI_Full] ON #full (UserNumber asc, [Month] asc);

create table #month ([Month] int);

insert into #month ([Month])
select [Month]
from #full
group by [Month];

CREATE UNIQUE CLUSTERED INDEX [CI_Month] ON #month ([Month] asc);

create table #start_usernumber (UserNumber int, [Month] int);

insert into #start_usernumber (UserNumber, [Month])
select UserNumber, min([Month])
from #full
group by UserNumber;

CREATE UNIQUE CLUSTERED INDEX [CI_StartUserNumber] ON #start_usernumber (UserNumber asc, [Month] asc);

select su.UserNumber,
       m.[Month],
       case when(f.ZIP is null) then (select top(1) f0.ZIP from #full as f0 where f0.UserNumber=su.UserNumber and f0.[Month]<m.[Month] and f0.ZIP is not null order by f0.[Month] desc) else f.ZIP end as ZIP
from #start_usernumber as su
inner join #month as m on su.[Month]<=m.[Month]
left join #full as f on m.[Month]=f.[Month] and su.UserNumber=f.UserNumber
order by su.UserNumber, m.[Month];

rollback tran

结果:

enter image description here

答案 1 :(得分:1)

至少在您构建完初始集之后,听起来像这样的事情就会起作用。这确实是假设该过程每个月都进行更新,以使该系列中不会出现空白:

EditInput

如果要填补空白,可以从一个空表开始,然后循环运行30多次。如果表名是可预测的,则类似这样的内容可能会生成整个脚本。

insert into Master (userid, month, zip)
select
    coalesce(u.userid, m.userid),
    coalesce(u.month, convert(char(6), dateadd(month, 1, m.month + '01'), 112),
    coalesce(u.zip, m.zip)
from ZipUpdate u full outer join Master m
    on m.userid = u.userid and m.month =
        convert(char(6), dateadd(month, -1, u.month + '01'), 112);