2016-02-08 18 views
0

我必須修改大型價格表,以便每篇文章只有一個有效價格。 有時銷售員工會插入新的價格,並忘記更改舊的無限有效日期。sql-query將所有validTo日期更改爲下一個validFrom日期減去一天

所以我必須寫一個SQL查詢來改變所有validTo日期到下一個validFrom日期減一天,當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 < 

回答

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。如果不是,則相應地更改語句。

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)。

於是:要麼完全刪除結束日期列或讓它不變。不要按照您的意圖更新它。如果您將記錄更新爲下一個日期減1,那麼您實際上會冗餘地保存數據,這可能會在稍後導致問題。

+0

有可能,有時間跨度沒有有效的價格。當有無限的有效價格,而另一個價格只有很短的有效期時,舊價格不能再次變爲有效。這就是我必須重新計算validTo日期的原因。 – tonirush

+0

價格可以對指定的跨度有效,例如10天或價格可以有效,直到添加新的價格。所以,當我放棄EndDate列時,我失去了這些信息。 – tonirush

+0

我明白了,有時候,當某個產品不可用時,您在這段時間內沒有給出價格。是的,當你放棄專欄時你會失去這些信息。你的桌子有兩個目的,1.當一個項目是/可用的,2.以什麼價格。我沒有看到這個。 –

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) 
     ;      
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';