编辑:大幅修改。
第一个解决方案没有考虑各个领域在不同时间发生变化所产生的问题。它只关心将最新更新应用于原始有效日期值。
这是对该答案的重写,返回,以便单独考虑正在更改的每个字段,而不是联合考虑。
所有 sql 都在 sqlfiddle 演示: http ://sqlfiddle.com/#!4/ca4f4/6
我们首先获取任何单个字段的最新更改。我们可以这样做:
select *
from ( select empid, when, what from updates
where when <= to_date('2012-05-10', 'yyyy-mm-dd')
) pivot_data
pivot ( max(when)
for what in ('region' as max_region_date,
'city' as max_city_date,
'country' max_country_date)
);
这会生成一个数据透视表,分别考虑每个字段,并给出小于或等于报告生效日期的最大日期的输出。请注意,由于此数据透视表已添加到较大的查询中,因此它只是嵌入报告日期的位置。
要向您的原始数据集添加更多数据,让我们使用:
EMPID NEW WHAT WHEN
1 germany region May, 01 2012
1 germany country May, 01 2012
1 münchen city May, 01 2012
2 boston city June, 01 2012
2 canada country July, 01 2012
2 toronto city July, 01 2012
2 vancouver city August, 01 2012
因此,如果您针对 15.August 的报告日期运行上述查询,您会得到:
EMPID MAX_REGION_DATE MAX_CITY_DATE MAX_COUNTRY_DATE
1 May, 01 2012 May, 01 2012 May, 01 2012
2 (null) August, 01 2012 July, 01 2012
(null) 表示 empid = 2 的区域在更新中没有条目。empid = 2 的另外两个日期表示该字段的最近更改日期。
现在,我们需要将其转换new
为每个字段在该日期的值。这可以通过以下方式完成:
select distinct u1.empid,
(select u2.new from updates u2
where u2.what = 'region'
and u2.empid = u1.empid
and u2.when = max_dates.max_region_date
) region, max_dates.max_region_date,
(select u3.new from updates u3
where u3.what = 'country'
and u3.empid = u1.empid
and u3.when = max_dates.max_country_date
) country, max_dates.max_country_date,
(select u4.new from updates u4
where u4.what = 'city'
and u4.empid = u1.empid
and u4.when = max_dates.max_city_date
) city, max_dates.max_city_date
from updates u1
left join
(select *
from ( select empid, when, what from updates
where when <= to_date('2012-07-15', 'yyyy-mm-dd')
) pivot_data
pivot ( max(when)
for what in ('region' as max_region_date,
'city' as max_city_date,
'country' max_country_date)
)
) max_dates on max_dates.empid = u1.empid;
我将上面的数据透视表输出嵌入为派生表,然后单独选择对应于特定日期的每个字段值。
使用 15.August 的报告运行此报告会给出:
EMPID REGION MAX_REGION_DATE COUNTRY MAX_COUNTRY_DATE CITY MAX_CITY_DATE
2 (null) (null) canada July, 01 2012 vancouver August, 01 2012
1 germany May, 01 2012 germany May, 01 2012 münchen May, 01 2012
对于员工 2,我们看到该国家/地区的值是加拿大,它在 01.July 更新,而最近的城市温哥华,在 01.August 更新。
现在,我们需要将其与针对员工的查询结合起来:
select e.empid, e.name,
(coalesce( u.region, e.region)) region,
(coalesce( u.city, e.city)) city,
(coalesce( u.country, e.country)) country
from employee e
left join (
select distinct u1.empid,
(select u2.new from updates u2
where u2.what = 'region'
and u2.empid = u1.empid
and u2.when = max_dates.max_region_date
) region, max_dates.max_region_date,
(select u3.new from updates u3
where u3.what = 'country'
and u3.empid = u1.empid
and u3.when = max_dates.max_country_date
) country, max_dates.max_country_date,
(select u4.new from updates u4
where u4.what = 'city'
and u4.empid = u1.empid
and u4.when = max_dates.max_city_date
) city, max_dates.max_city_date
from updates u1
left join
(select *
from ( select empid, when, what from updates
where when <= to_date('2012-08-15', 'yyyy-mm-dd')
) pivot_data
pivot ( max(when)
for what in ('region' as max_region_date,
'city' as max_city_date,
'country' max_country_date)
)
) max_dates on max_dates.empid = u1.empid
) u on u.empid = e.empid
order by e.empid;
其中最大的部分是派生表,如前所述。其余的是针对 的连接employee
,然后是 'coalesce ing to either take the updated value, or the current value in employee if the update value is
null`。
这导致:
EMPID NAME REGION CITY COUNTRY
1 james germany münchen germany
2 mike americas vancouver canada
当使用 15.August 的报告日期时。您可以在上面给出的 sqlfiddle 中根据我的测试数据(或添加您自己的数据)验证其他日期。
现在,最后一个问题。上面假设您有数据完整性约束来验证仅在将来进行更新——一旦将更新应用于员工表(从而更新它的有效日期字段),该行就会从更新表中删除。也就是说,更新仅包含未应用的更改。
如果我们想考虑这种情况,我们需要再次在 select 中逐个字段地检查它。将上面的选择修改为:
select e.empid, e.name,
(coalesce( (case
when (u.max_region_date > e.effective_date)
then u.region
end),
e.region)) region,
(coalesce( (case
when (u.max_city_date > e.effective_date)
then u.city
end),
e.city)) city,
(coalesce( (case
when (u.max_country_date > e.effective_date)
then u.country
end),
e.country)) country
from . . . . . the from in the previous query above . . .
在我的情况下,您会得到与以前相同的输出。
我应该补充一点,我同意 Glenn 关于不在您的列名中使用保留字when
的意见。new
(虽然我把它们留在了我的样本中。)