【问题标题】:SQL Job for updating datetime in a table用于更新表中日期时间的 SQL 作业
【发布时间】:2014-03-31 19:33:37
【问题描述】:

我有一张表,其中包含我想要维护的演示数据。表中的数据包含日期时间,我想创建一个每晚运行以更新日期时间的作业,以便日期时间永远不会超过 1 周,并且永远不会是当前日期时间之后的未来日期时间。我想在按日期时间排序时保持消息的顺序,这样当我更新该列时,一行永远不会越过另一行。如果没有一些行最终在按日期时间排序时跨越,我无法想出一个公式来做到这一点。 有什么建议吗?

我的问题在于公式。 如果日期为星期二下午 5 点,则向所有人添加一天仍将使其成为最后一条消息的未来日期,并且我添加 1 天,然后在星期三早上进行演示时,它将是星期三下午 5 点。 除了最近的一天之外,添加一天可能会跳过下一个最近的一天,导致最近的消息回退到顺序中。

【问题讨论】:

  • 您应该发布您的数据现在的样子以及您期望它的样子。这很难想象。您在设置工作或编写查询时遇到问题吗?
  • 如果作业每晚运行,为什么不给每个日期时间值加 1 天? DATEADD (day, 1, <datetime-field>)。然后一切都保持同步。还是您无法识别所有需要更新的日期时间字段?
  • 您是否全天都在表中插入新行,以及运行每晚更新?或者这是一组仅在夜间更新的静态行,仅此而已?
  • 我们在演示期间插入行。
  • 您使用的是哪个 DBMS?后格雷斯?甲骨文?

标签: sql-server datetime sql-server-2005 jobs


【解决方案1】:

如果您目前有多个跨越一周以上的日期,则无法通过简单地在每个日期上添加时间来实现。如果记录之间的时间范围无关紧要,只有顺序、最小值和最大值,我将使用 row_number 函数对日期进行排序,并将该排序数字(以秒为单位)添加到 1 周前:

update t
    set t.YourDateColumn = u.NewDate
    from YourTable t
        inner join  (select ID,
                        dateadd(second,
                            row_number() over(order by YourDateColumn),
                            dateadd(week,-1,getdate())) NewDate
                     from YourTable
                     ) u
            on u.ID = t.ID

如果您有多达 604.8K 条记录,这将起作用。如果你有更多,你将不得不添加毫秒。这将适用于多达 6.048 亿条记录。

【讨论】:

    【解决方案2】:

    假设您使用的是 MySQL,因为您没有指定(尽管几乎在任何地方都可以使用相同的技术,但使用的确切语法和函数会有所不同)

    给定这样的表结构

    CREATE TABLE T (
      id int auto_increment primary key, 
      detail varchar(20), 
      date datetime
    );
    
    INSERT INTO T
      (detail, date)
    VALUES
      ('one', NOW()),
      ('two', DATE_SUB(NOW(), INTERVAL 1 day)),
      ('three', DATE_SUB(NOW(), INTERVAL 2 day)),
      ('four', DATE_SUB(NOW(), INTERVAL 3 day)),
      ('five', DATE_SUB(NOW(), INTERVAL 4 day));
    

    您可以按正确的顺序选择所有行,并在此过程中重新平均分配前一周的日期。像这样:

    SELECT 
      T.*, 
      DATE_SUB(NOW(), INTERVAL 6.048e+11*(1-(@row := @row + 1)/@tot) MICROSECOND) as newDate 
    FROM 
      T, 
      (SELECT @row := 0, @tot := (select count(*) from T)) r 
    ORDER BY 
      date;
    

    注意:6.048e+11 是一周中的微秒数。

    这是一个例子:http://sqlfiddle.com/#!2/939bc/5

    因此,您可以使用该投影来创建一个临时表,然后删除原始表,并根据临时表中的值重新创建它。像这样的:

    create temporary table T2 as (
      select 
        T.*, 
        DATE_SUB(NOW(), INTERVAL 6.048e+11*(1-(@row := @row + 1)/@tot) MICROSECOND) as newDate
      from T, (SELECT @row := 0, @tot := (select count(*) from T)) r 
      order by date
    );
    drop table T;
    create table T as (select id, detail, newDate as date from T2);
    

    更新: 将上面的示例更改为使用 MICROSECOND 粒度,因为前面的示例使用小数 DAY 间隔,mysql 似乎不支持。我也相应地更新了 sqlfiddle 链接。

    此外,更正了公式以按正确顺序排列日期(前面的示例要求按相反顺序分配日期)。

    【讨论】:

      猜你喜欢
      • 2017-04-22
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 2013-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-23
      相关资源
      最近更新 更多