我必须修改一个大的价格表,这样每篇文章只有一个有效价格。 有时销售人员会插入新价格而忘记更改旧的无限有效日期。
因此,当validTo日期具有无限有效性(9999-12-31)时,我必须编写一个sql-query来将所有validTo日期更改为下一个validFrom日期减去一天。 但是我不知道如何只使用SQL(Oracle 12)来实现这一点。
anr price validFrom validTo
1 447.1 2015-06-01 9999-12-31 <
1 447.2 2015-06-16 2015-06-16
1 447.3 2015-06-17 2015-06-17
1 447.4 2015-06-22 2015-06-22
1 447.5 2015-07-06 9999-12-31 <
1 395.0 2015-07-20 2015-07-20
1 447.6 2015-08-03 9999-12-31 <
1 447.7 2015-08-17 9999-12-31 <
1 447.8 2015-08-24 9999-12-31 <
1 395.0 2015-09-07 2015-09-07
1 450.9 2015-11-15 9999-12-31 < no change because it is the last entry
更新表后,结果应该是
anr price validFrom validTo
1 447.1 2015-06-01 2015-06-15 <
1 447.2 2015-06-16 2015-06-16
1 447.3 2015-06-17 2015-06-17
1 447.4 2015-06-22 2015-06-22
1 447.5 2015-07-06 2015-07-19 <
1 395.0 2015-07-20 2015-07-20
1 447.6 2015-08-03 2015-08-16 <
1 447.7 2015-08-17 2015-08-23 <
1 447.8 2015-08-24 2015-09-06 <
1 395.0 2015-09-07 2015-09-07
1 450.9 2015-11-15 9999-12-31 <
答案 0 :(得分:2)
为了更新结束日期,您只需选择所有较高开始日期的最小值。
update mytable upd
set enddate = coalesce(
(
select min(startdate) - 1
from mytable later
where later.startdate > upd.startdate
and later.anr = upd.anr -- same product
), date'9999-12-31') -- coalesce for the case there is no later record
where enddate = date'9999-12-31';
我已将anr
作为产品ID。如果不是,则相应地更改声明。
答案 1 :(得分:1)
Oracle提供了一个分析函数LEAD
,它在给定排序标准的情况下引用当前加第n个记录。此函数可用于在更新语句中选择正确的日期值,如下所示(让test_prices
为表名,ppk
其PK):
update test_prices p
set p.validTo = (
select ps.vtn
from (
select lead ( p1.validFrom, 1 ) over ( order by p1.validFrom ) - 1 vtn
, ppk
from test_prices p1
) ps
where ps.ppk = p.ppk
)
where to_char(p.validTo, 'YYYY') = '9999'
and p.validFrom != ( select max(validFrom) from test_prices )
;
答案 2 :(得分:1)
UPDATE VALID_DATES v
SET validTo = (
SELECT validTo
FROM (
SELECT anr,
validFrom,
COALESCE(
LEAD( validFrom - 1, 1 ) OVER ( PARTITION BY anr ORDER BY validFrom ),
validTo
) AS validTo
FROM valid_dates
) u
WHERE v.anr = u.anr
AND v.validFrom = u.validFrom
)
WHERE validTo = DATE '9999-12-31';
答案 3 :(得分:0)
有两种可能性:
<强> 1。明确的时间跨度
price validFrom validTo 90.99 2016-01-01 9999-12-31 80.00 2016-01-16 2016-01-17
第一个价格在1月16日之前和1月17日之后有效,而第二个价格仅在1月份的两天有效。
更改第一个validTo将是一个非常糟糕的主意。
<强> 2。隐含时间跨度
price validFrom 90.99 2016-01-01 80.00 2016-01-16 90.99 2016-01-18
此数据表示与显式时间跨度示例中的数据相同。第一个价格在1月16日之前有效,然后第二个价格有效到1月17日,之后下一个价格(再次等于第一个价格)有效。在这里,您不需要EndDate,因为它是隐含的。 当然第一个价格仅在1月15日之前有效,因为从1月16日起还有另一个价格有效(记录#2)。
所以:完全删除EndDate列或让它不受影响。不要像你想要的那样简单地更新它。如果你将记录更新到下一个日期减1,你实际上会冗余地保存数据,这可能会导致以后出现问题。