简体   繁体   English

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

[英]sql-query that change all validTo dates to the next validFrom date minus one Day

I have to modify a big pricelist table so that there is only one valid price for every article. 我必须修改一个大的价目表,以便每篇文章只有一个有效的价格。 Sometimes the sales employees insert new prices and forgot to change the old infinite validTo dates. 有时,销售员工会插入新价格,却忘记更改旧的无限有效日期。

So I have to write a sql-query to change all validTo dates to the next validFrom date minus one day, when the validTo date has infinite validity (9999-12-31). 因此,我必须编写一个sql查询以将所有validTo日期更改为下一个有效起始日期减去某一天,即有效日期具有无限有效性(9999-12-31)。 But I have no idea how can i reach this with only SQL (Oracle 12). 但是我不知道如何仅使用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

after updating the the table, the result should look like 更新表格后,结果应如下所示

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 <

In order to update an end date you can simply select the minimum of all higher start dates. 为了更新结束日期,您只需选择所有较高开始日期中的最小值即可。

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

I have taken anr to be the product id. 我已将anr作为产品ID。 If it isn't then change the statement accordingly. 如果不是,则相应地更改该语句。

Oracle provides an analytic function LEAD that references the current-plus-n-th record given a sort criterion. Oracle提供了一种分析功能LEAD ,该函数在给定排序标准的情况下引用了当前第n条记录。 This function may serve the purpose of selecting the proper date value in an update statement as follows ( let test_prices be the table name, ppk its PK ): 此函数可以用于在更新语句中选择适当的日期值,如下所示(让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';

There are two possibilities: 有两种可能性:

1. Explicit time spans 1.明确的时间跨度

price   validFrom   validTo
90.99   2016-01-01  9999-12-31
80.00   2016-01-16  2016-01-17

The first price would be valid both before January 16 and after January 17, whereas the second price was only valid on two days in January. 第一个价格在1月16日之前和1月17日之后均有效,而第二个价格仅在1月的两天内有效。

It would then be a very bad idea to change the first validTo. 更改第一个validTo将是一个非常糟糕的主意。

2. Implicit time spans 2.隐式时间跨度

price   validFrom 
90.99   2016-01-01
80.00   2016-01-16
90.99   2016-01-18

This data represents the same as in the explicit time spans example. 此数据表示与显式时间跨度示例中的相同。 The first price is valid before January 16, then the second price is valid until January 17, and afterwards the next price (which equals the first price again) is valid. 第一个价格在1月16日之前有效,然后第二个价格在1月17日之前有效,然后第二个价格(再次等于第一个价格)有效。 Here you don't need an EndDate, because it's implicit. 在这里,您不需要EndDate,因为它是隐式的。 Of course the first price is only valid until January 15, because from January 16 there is another price valid (record #2). 当然 ,第一个价格仅在1月15日之前有效,因为从1月16日起还有另一个价格有效(记录2)。

So: Either remove the EndDate column completely or let it untouched. 因此:完全删除EndDate列,或使其保持不变。 Don't simply update it, as you have intended. 不要像您打算的那样简单地对其进行更新。 If you updated your records to next date minus one, you would actually hold data redundantly, which might lead to problems later. 如果将记录更新为下一个日期减去一个记录,则实际上将多余地保存数据,这可能会在以后导致问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM