【问题标题】:How to increment DateTime column by a second for every row?如何为每一行将 DateTime 列增加一秒?
【发布时间】:2013-03-28 21:52:33
【问题描述】:

假设我有这个时间值:09:00:00

我有一个包含时间列的表,其中包含三条记录。

我想用那个时间更新这 3 条记录,但每次(对于每条记录)时间值都会增加一秒。

类似这样的:

ColumnA   ColumnB
1         09:00:00
2         09:00:01
3         09:00:02

我该怎么做?

我的解决方案:

在我自己的解决方案工作了一段时间后,这就是我想出的

update tor1
set ColumnB = dateadd(s,tor2.inc, ColumnB)
from table1 tor1
inner join (select ColumnA, ROW_NUMBER() OVER (Order by ColumnA) as inc from table1) tor2 on tor1.ColumnA=tor2.ColumnA

【问题讨论】:

  • 如果我们不能使用ColumnA来订购,你如何建议我们知道哪一行加0秒,哪一行加1,哪一行加2?表是一组无序的行,因此如果您想要一个可预测的结果,您需要指明该顺序是如何定义的。
  • 假设ColumnA 是PK,它是身份。现在假设第 2 条记录被删除了,你会给第 3 行加 2 秒吗?
  • 您是否在问自己自己的要求是什么?
  • 我只想将秒 (1++) 添加到该列 B,而不管其他列。第一行,同一时间,第二行+1,第三行2,以此类推
  • @Somebody 既然你已经有了答案,那么十亿美元的问题就是你为什么要这样做?

标签: sql sql-server sql-server-2000


【解决方案1】:

您没有指定任何特定的顺序。

对于不确定/未记录的结果,您可以尝试古怪的更新方法。

CREATE TABLE table1
(
    ColumnB datetime NULL
);

INSERT INTO table1 DEFAULT VALUES;
INSERT INTO table1 DEFAULT VALUES;
INSERT INTO table1 DEFAULT VALUES;

DECLARE @ColumnB datetime;

SET @ColumnB = '19000101 09:00:00';

UPDATE table1
SET @ColumnB = ColumnB = DATEADD(s, 1, @ColumnB);

SELECT *
FROM table1;

DROP TABLE table1;

否则,您将需要使用光标或找到某种方法来模拟 2000 年的ROW_NUMBER

【讨论】:

【解决方案2】:

这是一个使用 #temp 表但不使用不受支持的古怪更新(无意冒犯 Martin)并且不依赖于无法保证的神奇身份排序的版本(无意冒犯 Richard)。

CREATE TABLE dbo.Whatever
(
  ColumnA INT IDENTITY(1,1), 
  ColumnB DATETIME
);

INSERT dbo.Whatever(ColumnB) SELECT '09:00';
INSERT dbo.Whatever(ColumnB) SELECT '09:00';
INSERT dbo.Whatever(ColumnB) SELECT '09:00';
INSERT dbo.Whatever(ColumnB) SELECT '09:00';
INSERT dbo.Whatever(ColumnB) SELECT '09:00';

-- just to demonstrate a gap
DELETE dbo.Whatever WHERE ColumnA = 3;

SELECT w.ColumnA, w.ColumnB, 
  c = (SELECT COUNT(*) FROM dbo.Whatever WHERE ColumnA < w.ColumnA)
INTO #x
 FROM dbo.Whatever AS w;

UPDATE w
  SET ColumnB = DATEADD(SECOND, x.c, w.ColumnB)
  FROM dbo.Whatever AS w
  INNER JOIN #x AS x
  ON x.ColumnA = w.ColumnA;

SELECT ColumnA, ColumnB FROM dbo.Whatever;

结果:

ColumnA  ColumnB
-------  -----------------------
1        1900-01-01 09:00:00.000
2        1900-01-01 09:00:01.000
4        1900-01-01 09:00:02.000
5        1900-01-01 09:00:03.000

【讨论】:

  • 可能不建议用于大型表,因为 SELECT COUNT(*) 子查询使其 O(n^2)。但否则一个很好的解决方案如果 ColumnA 是唯一的(OP 没有说明)。
  • OP 声明它是一个身份列。虽然这本身并不能保证唯一性,但我只看到由于故意破坏或极端愚蠢而导致的重复。
  • OP 提出了一个问题“如果......是一个身份”。 OP还在mattedgod的回答下说“认为该列甚至不存在”。当然,在这种情况下我的解决方案也行不通
【解决方案3】:

如果您可以假设 ColumnA 是您需要添加的秒数(或像您的示例那样成正比),那么您可以使用它。

UPDATE myTable SET ColumnB = DATEADD(s, (ColumnA - 1), ColumnB)

如果没有,您将需要确定每列的排名(谷歌上有很多结果)并添加排名。

【讨论】:

  • 遗憾的是,我不能将该列用作增量值。此外认为该列甚至不存在
  • @Somebody 哪一栏不存在? A 列?您将其包含在示例中...如果不是 ColumnA,请提供一种确定顺序的方法,我们还应该如何知道?
【解决方案4】:

对于 SQL Server 2005 及更高版本,您可以使用 OVER 子句来控制更新的顺序。

;with T as (
    select *, rn=row_number() over (order by columnA)
    from Tbl)
update T
    set columnB = DateAdd(s, rn-1, '09:00:00');

SQL Fiddle

对于 SQL Server 2000,您可以使用临时表。使用INSERT INTO..SELECT to guarantee IDENTITY 列的计算。

CREATE TABLE table1
(
    ColumnA int,
    ColumnB datetime NULL
);

INSERT INTO table1 values (1, null);
INSERT INTO table1 values (2, getdate());
INSERT INTO table1 values (3, '02:02:02');

create table #tmp (ColumnA int, ID int identity(0,1))

insert into #tmp
select ColumnA
from table1
order by ColumnA;

update a
set ColumnB = dateadd(s,t.ID,'09:00:00')
from #tmp t
join table1 a on a.ColumnA = t.ColumnA;

select * from table1;

【讨论】:

  • 这是一个定义了 IDENTITY 列的表。您正在使用不同的 IDENTITY 函数。 support.microsoft.com/default.aspx?scid=kb;en-us;Q273586
  • 我认为也可能存在涉及并行性和身份值分配方式的错误,所以如果你要依赖你所观察到的,请使用MAXDOP 1。对于 OP 的示例(三行),这不是问题,但我们真的不知道我们在谈论多少行。
  • @RichardTheKiwi - 我认为 Aaron 的观点是文章保证顺序但不保证顺序。
  • 另见sqlmag.com/article/sql-server/…(关于 IDENTITY() 函数)。
  • @Aaron 我想我们已经在几条评论前移除了 IDENTITY() 函数
猜你喜欢
  • 1970-01-01
  • 2022-11-16
  • 1970-01-01
  • 1970-01-01
  • 2015-09-13
  • 1970-01-01
  • 2021-12-19
  • 2022-01-20
  • 1970-01-01
相关资源
最近更新 更多