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

How to update a flag for all rows except the last 5 with the latest dates?

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

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,并将时间戳列 Dttm 设置为 8/3/2018 8:30:00.000000 AM。现在 table 看起来像这样:

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

我想编写一个更新查询,将 table 中所有列的 New_Flag 列设置为 0,但最近日期为 5 的列除外:ID #1,# 5、#2、#7,以及#4 或#6。第5条记录选#4还是#6都无所谓,只要返回5条即可。

这就是 table 最终的样子(我任意选择 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 查询中执行此操作(最好不要在存储过程中执行)?有没有更有效的方法来实现我想要完成的目标?

谢谢。

我想你可以用 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
                 );

虽然 Gordon 的回答不是很准确,但他确实帮助我走上了正确的道路。

这是我想出的解决方案:

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 个最近的记录之一更新,它将被忽略。

这将适用于最新版本的 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