【问题标题】:Update a TIMESTAMP column to be nullable将 TIMESTAMP 列更新为可为空
【发布时间】:2014-07-15 20:20:30
【问题描述】:

我有一个存在于两个数据库中的表。

在一个数据库中,有一个表,其列名为ROW_VERSION,其类型为TIMESTAMP NOT NULL

在第二个数据库中,同一个表具有相同类型的TIMESTAMP 列,但它的类型是TIMESTAMP NULL

我想将第一个数据库中的列更改为可为空。这将使我能够更轻松地在两个数据库之间进行同步。

但是当我运行这个时:

ALTER TABLE [MyTable]
ALTER COLUMN ROW_VERSION TIMESTAMP NULL

我得到错误:

无法将列“ROW_VERSION”更改为数据类型时间戳。

它已经是一个时间戳。 我只需要将其设为可空即可。有没有办法做到这一点?

【问题讨论】:

  • 列是主键吗?
  • @DMason - 不,不是。
  • 如果你在你的 tsql 中把timestamp 换成rowversion,那会起作用吗?我相信这两种数据类型是等价的......时间戳已被弃用,并且在未来的某个地方,它不会出现在 SQL Server 的未来版本中。
  • @KrisGruttemeyer,您提到的 SO 问题是针对 MySQL 的。
  • @DMason - 我在使用 rowversion 时收到相同的错误消息。

标签: sql-server tsql sql-server-2012


【解决方案1】:

我不认为你可以。而且一张表只能有一个时间戳列。

您也无法更新时间戳列,因此旧的“复制/删除/更新”技巧将不起作用。

你很可能会坚持你所拥有的。

create table #tmp (id int, timestamp null)
insert into #tmp (id) values (1)
select * from #tmp


create table #tmp2 (id int)
insert into #tmp2 (id) values (1)
alter table #tmp2 add timestamp null
select * from #tmp2

我正在测试 NULL TIMESTAMP 列,它实际上不会为 NULL——我找不到任何说明它的文档,但我认为 NULL TIMESTAMP 是不可能的(即使声明为 null,它也永远不会为 null数据)。

timestamp 是 rowversion 数据类型的同义词,是主题 数据类型同义词的行为。在 DDL 语句中,使用 尽可能使用 rowversion 而不是时间戳。更多 信息,请参阅数据类型同义词 (Transact-SQL)...

http://msdn.microsoft.com/en-us/library/ms182776(v=sql.110).aspx

还有……

ALTER COLUMN 指定命名列将被更改或 改变。修改后的列不能是以下任何一项:A 具有时间戳数据类型的列...

http://msdn.microsoft.com/en-us/library/ms190273(v=sql.110).aspx

【讨论】:

  • 唉,当我尝试将 ROW_VERSION 插入不同的表时,我收到此错误:Cannot insert an explicit value into a timestamp column. Use INSERT with a column list to exclude the timestamp column, or insert a DEFAULT into the timestamp column.
  • 是的,即使您在数据在表中之后添加列,当您添加时间戳时,它也会填充每一行。显然该列不会包含 NULL 值。
  • @Vaccano,如果您只是从一个盒子合并到另一个盒子,我会从列列表中省略 row_version 并让目标服务器处理它的自动填充。您还可以将合并设置为仅在数据已更改时才更新。我倾向于比较所有列而不是更新所有列,无论它们是否需要。如果您想要样品,请说出来,我会添加它。
  • 我最终研究并发现,由于它在我的开发环境中,时间戳列没有被任何外部或内部系统使用。一旦知道这一点,我就可以删除该列并使用匹配的 nullablilty 重新添加它。不知道为什么我的数据仓库团队使用可以为空的时间戳列(因为就像你说的,你永远不能插入空值)。但是只要它们匹配我的比较工具就可以生成脚本来升级测试数据库以匹配开发者。感谢您的帮助!
【解决方案2】:

您不能更改 TIMESTAMP 列 (http://msdn.microsoft.com/en-us/library/ms190273.aspx) 您必须采用迂回的方式重命名旧表,使用所需架构创建新表,插入重命名表中的数据,然后删除旧表。如果您更改 GUI 中的列,SSMS 可能会为您编写脚本。

更改列
指定要更改或更改的命名列。

修改后的列不能是以下任何一种:

•具有时间戳数据类型的列。

【讨论】:

    【解决方案3】:

    是的,你不能这样做。如果您希望该列可以为空,则几乎听起来您想对该列使用日期或日期时间数据类型。我认为 TIMESTAMP 类似于 IDENTITY 数据类型,因为它们都是自填充、自动递增的列,它们为 null 并没有任何意义。另请注意,如果您尝试以下操作:

    if object_id('tempdb..#timestamptable') is not null 
        drop table #timestamptable
    create table #timestamptable (id int, ts timestamp null)
    insert into #timestamptable (id, ts)
    values(1, null),
    (2, null)
    select *
    from #timestamptable
    

    您的时间戳列仍会有数据:

        id      ts
        1       0x000000004C8BED2B
        2       0x000000004C8BED2C
    

    【讨论】:

    • 我不在乎它们是否可以为空。我的数据库团队把它们放在那里。我需要从我的开发环境合并到我的测试环境。该合并脚本想要删除并重新创建表,因为可空性不匹配。本来应该很简单的脚本现在变得非常复杂和冒险。
    【解决方案4】:

    我正在运行 Postgres SQL,以下对我有用

    `ALTER TABLE MYTABLE COLUMN MYROW DROP NOT NULL`
    

    【讨论】:

      【解决方案5】:

      强制类型 更改表 [MyTable] ALTER COLUMN ROW_VERSION TIMESTAMP

      如果存在则删除索引

      ALTER TABLE SOMETABLE DROP CONSTRAINT DF__SOME__index

      也许添加默认值

      ALTER TABLE [MyTable] 为 ROW_VERSION 添加默认值 0

      如果允许,我将删除表格并重新创建

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-03
        • 2016-04-23
        • 2019-08-23
        • 1970-01-01
        • 1970-01-01
        • 2011-11-16
        • 1970-01-01
        • 2012-12-26
        相关资源
        最近更新 更多