在包含记录的现有表中,如何创建一个新的 datetime2(2) 列并使用基于另一列的值填充它?

Posted

技术标签:

【中文标题】在包含记录的现有表中,如何创建一个新的 datetime2(2) 列并使用基于另一列的值填充它?【英文标题】:In an existing table with records, how do I create a new datetime2(2) column and populate it with values based on another column? 【发布时间】:2020-07-25 06:18:26 【问题描述】:

我有一个 VARCHAR 列,如下所示:

Created_DTM
-----------
2020-02-05 16:26:45.00Z
2020-02-16 08:55:52.00Z
2020-04-24 15:24:01.00Z
2020-06-13 22:14:18.00Z

如何编写一个脚本来创建一个名为 Created_DTM_Converted 的新列,并用一个值填充每条记录,以便 zulu (Z) 字符消失,同时减去 5 小时以匹配我的时区?

我的尝试:

这个查询给出了我需要的确切值:

SELECT dateadd(hh, -5, convert(datetime2(2), Created_DTM, 120)) AS Created_DTM_Converted
FROM dbo.table

这是输出:

Created_DTM_Converted
-----------
2020-02-05 11:26:45.00
2020-02-16 03:55:52.00
2020-04-24 10:24:01.00
2020-06-13 17:14:18.00

但我不知道如何编写一个可以执行一次并使其成为永久添加的列的脚本。我该怎么做?

【问题讨论】:

如果现有created_DTM 列中的值发生变化,您是否希望新列的值发生变化?或者这是一次性练习(例如,您打算删除现有列)? 后者是正确的:我打算稍后删除现有的列。 【参考方案1】:

您可以更改您的表并将这个新列添加为计算列:

ALTER TABLE dbo.table
ADD COLUMN Created_DTM_Converted AS DATEADD(hh, -5, CONVERT(datetime2(2), Created_DTM, 120));

请注意,上面的计算列是虚拟的,这意味着它实际上并没有存储在数据库中,而是在访问时动态计算。

顺便说一句,减去 5 小时的一种可能更简单的方法可能是取时间戳的前 22 个字符:

SELECT DATEADD(hh, -5, LEFT(Created_DTM, 22))
FROM dbo.table;

这似乎也有效。

编辑:

出于几个原因,我建议反对删除原始的 Created_DTM 列。首先,它代表原始源数据,通常最好保留尽可能多的状态。其次,假设新记录将以这种原始格式插入,那么您需要维护此列。在这种情况下,在您的桌子上构建某种视图是合适的。

【讨论】:

根据 OP 提供的附加评论,他们打算删除原始列,因此此处不能使用计算列。 虚拟列的重点是能够以某种方式查看您的数据,而无需为其提交任何空间。对于非持久计算列,没有什么可以“删除”。 OP 打算删除 existing Created_DTM 列。这在原始问题中没有指定,它在随后的评论中,我猜这里可能的用例是他们做出了明智的决定,将datetime 值存储为实际的datetime 值而不是 varchar 并且正在清理增加一些技术债务,最终将涉及删除varchar 列,但这样做他们显然希望保留现有数据。 @allmhuran 你是对的,该列当前是 varchar 并且已经以这种方式收集数据太久了,所以我正在尝试清理它。我更愿意将数据实际存储在专用的“日期时间”列中,并在以后删除 varchar 列。 @Nixu 好的...但是当新数据稍后出现并且该列已被删除时会发生什么?【参考方案2】:

由于您在评论中提到您打算从旧列计算新列,并打算稍后删除旧列,因此您将无法使用 Tim 的计算列答案。

因此,您需要分两步执行此过程。首先添加列,然后用值填充它。您可以稍后作为第三步删除原始列。

alter table dbo.table add Created_DTM_Converted datetime2(2) null;
go

update dbo.table
set    Created_DTM_Converted = dateadd(hh, -5, convert(datetime2(2), Created_DTM, 120));

填充列后,您可以选择更改其定义以不允许空值:

alter table dbo.table alter column Created_DTM_Converted datetime2(2) not null;

【讨论】:

也可以使用计算列,因为它当然也可以被删除。 @TimBiegeleisen 好的......所以让我在这里理解你的想法。 OP 有他们需要的数据。它当前存储在他们打算删除的列中。他们创建一个计算列,以基于该现有列存储其数据的某种新表示。在将来的某个时候,他们会删除计算列,然后是原始列。我有一个问题,蒂姆。他们的数据去哪儿了?

以上是关于在包含记录的现有表中,如何创建一个新的 datetime2(2) 列并使用基于另一列的值填充它?的主要内容,如果未能解决你的问题,请参考以下文章

如何将现有表中的 7000 条记录中的前 1000 条记录复制到其他新表中

如何在现有表的中间插入新的数据库记录?

从现有数据库创建一个新的 MySQL 数据库,每个表最多包含 10000 行数据

如何将包含现有行和新行的新列添加到表中?

如何基于现有镜像创建新的 docker 镜像,但包含更多 Python 包?

如何在不包含新列名和类型的情况下更改现有 Hive 表中的列注释?