sql-query将所有validTo日期更改为下一个validFrom日期减去一天

时间:2016-02-08 09:02:48

标签: sql oracle

我必须修改一个大的价格表,这样每篇文章只有一个有效价格。 有时销售人员会插入新价格而忘记更改旧的无限有效日期。

因此,当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 <

4 个答案:

答案 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,你实际上会冗余地保存数据,这可能会导致以后出现问题。