![](/img/trans.png)
[英]Insert into history table and selecting validFrom and validTo dates based on table contents
[英]sql-query that change all validTo dates to the next validFrom date minus one Day
我必須修改一個大的價目表,以便每篇文章只有一個有效的價格。 有時,銷售員工會插入新價格,卻忘記更改舊的無限有效日期。
因此,我必須編寫一個sql查詢以將所有validTo日期更改為下一個有效起始日期減去某一天,即有效日期具有無限有效性(9999-12-31)。 但是我不知道如何僅使用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 <
為了更新結束日期,您只需選擇所有較高開始日期中的最小值即可。
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。 如果不是,則相應地更改該語句。
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 )
;
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';
有兩種可能性:
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列,或使其保持不變。 不要像您打算的那樣簡單地對其進行更新。 如果將記錄更新為下一個日期減去一個記錄,則實際上將多余地保存數據,這可能會在以后導致問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.