如何更新除最后5个最近日期以外的所有行的标志?

时间:2018-08-03 14:48:05

标签: sql db2 db2-luw

我有一个DB2 LUW 9.7表,看起来像这样(更新之前):

Id     SubId     Name     New_Flag      Dttm
-----------------------------------------------------------------------
  1        2      Sam            0      5/31/2017 1:30:00.000000 PM
  2        3      Joe            1      4/25/2018 12:30:00.000000 PM
  3        4      Ann            1      4/3/2018 2:10:00.000000 PM
  4        5      Tim            1      4/3/2018 2:15:00.000000 PM
  5        6      Tom            0      3/6/2017 2:00:00.000000 PM
  6        7      Art            1      4/3/2018 2:15:00.000000 PM
  7        8      Jen            1      4/25/2018 12:30:00.000000 PM
  8        9      Jim            1      4/3/2018 2:10:00.000000 PM
  ....many more records where New_Flag = 0

因此,我将ID#1和#5的New_Flag列更新为等于1,并将timestamp列Dttm设置为8/3/2018 8:30:00.000000 AM。现在表看起来像这样:

Id     SubId     Name     New_Flag      Dttm
-----------------------------------------------------------------------
  1        2      Sam            1      8/3/2018 8:30:00.000000 AM
  2        3      Joe            1      4/25/2018 12:30:00.000000 PM
  3        4      Ann            1      4/3/2018 2:10:00.000000 PM
  4        5      Tim            1      4/3/2018 2:15:00.000000 PM
  5        6      Tom            1      8/3/2018 8:30:00.000000 AM
  6        7      Art            1      4/3/2018 2:15:00.000000 PM
  7        8      Jen            1      4/25/2018 12:30:00.000000 PM
  8        9      Jim            1      4/3/2018 2:10:00.000000 PM
  ....many more records where New_Flag = 0

我想编写一个更新查询,该查询会将表中所有列的New_Flag列设置为等于0,但最新日期为5的除外:ID#1,#5,#2,#7,或者#4或#6。选择#4或#6作为第五条记录并不重要,只要返回5条记录即可。

这就是表的最终外观(我随意选择ID#6作为将New_Flag设置为0的记录之一):

Id     SubId     Name     New_Flag      Dttm
-----------------------------------------------------------------------
  1        2      Sam            1      8/3/2018 8:30:00.000000 AM
  2        3      Joe            1      4/25/2018 12:30:00.000000 PM
  3        4      Ann            0      4/3/2018 2:10:00.000000 PM
  4        5      Tim            1      4/3/2018 2:15:00.000000 PM
  5        6      Tom            1      8/3/2018 8:30:00.000000 AM
  6        7      Art            0      4/3/2018 2:15:00.000000 PM
  7        8      Jen            1      4/25/2018 12:30:00.000000 PM
  8        9      Jim            0      4/3/2018 2:10:00.000000 PM
  ....many more records where New_Flag = 0

我编写了以下代码来获取5条记录,但是我很难将其转换为UPDATE查询,该查询会将除这5条记录之外的每一行的New_Flag列设置为0:

select distinct
    name,
    older
from
    (
        select
            t1.name,
            t1.dttm as older
        from
            myTable t1
            left outer join
            myTable y1 on
                y1.new_flag = t1.new_flag
                and y1.dttm < t1.dttm
        where
            t1.new_flag = 1
        order by
            2 desc
    )
fetch first 5 rows only
;

是否可以在UPDATE查询中执行此操作(最好不在存储过程中执行此操作)?有没有更有效的方法来实现我要完成的任务?

谢谢。

3 个答案:

答案 0 :(得分:0)

我认为您可以使用fetch / offset来做到这一点:

update mytable
   set flag = 0
   where dttm < (select t2.dttm
                  from mytable t2
                  order by t2.dttm desc
                  offset 4 fetch first 1 row only
                 );

编辑:

如果以上版本在您的版本中不起作用,则可能是这样:

update mytable
   set flag = 0
   where dttm < (select t2.dttm
                  from (select t2.*, row_number() over (order by t2.dttm desc) as seqnum
                        from mytable t2
                       ) t2
                  where seqnum = 5
                 );

答案 1 :(得分:0)

虽然戈登的答案还不是很明确,但他确实帮助我走上了正确的道路。

这是我想出的解决方案:

update myTable t1
set new_flag = 0
where not exists (
    select 
        1
    from
        (
            select
                st2.*,
                row_number() over (order by st2.dttm desc) as seqnum
            from
                myTable st2
            where
                new_flag = 1
        ) t2
    where
        seqnum <= 5
        and t1.name = t2.name
);

这应该确保,如果一条记录的New_Flag = 0且Dttm比最新的前5条记录之一更新,则它将被忽略。

答案 2 :(得分:0)

这将在最新版本的Db2 LUW上运行,并且可以说是实现所需目标的最简洁的方法

update 
(   select
        new_flag 
    from 
    (   select 
            new_flag
        ,   row_number() over (order by dttm desc) as seqnum
        from
            myTable t
    )
    where
        seqnum <= 5
    and new_flag <> 0
)
set new_flag = 0