SQL ERROR : Column already has a DEFAULT bound to it

SQL ERROR : Column already has a DEFAULT bound to it

我有一个如下所示的 table,默认值列为 [IsProcessed]

IF NOT EXISTS (SELECT * FROM sys.objects 
               WHERE object_id = OBJECT_ID(N'[dbo].[Kovair_JileEventHistory]') 
                 AND type in (N'U'))
BEGIN
    CREATE TABLE [dbo].[Kovair_JileEventHistory]
    (
        [Id] [bigint] IDENTITY(1,1) NOT NULL,
        [GeneratedActionId] [char](36) NOT NULL,
        [BaseUrl] [nvarchar](255) NOT NULL,
        [ProjectName] [nvarchar](255) NOT NULL,
        [EntityName] [varchar](255) NOT NULL,
        [EntityId] [varchar](255) NOT NULL,
        [RelatedEntityName] [varchar](255) NOT NULL,
        [RelatedEntityId] [varchar](255) NOT NULL,
        [ActionName] [varchar](255) NOT NULL,
        [LoopbackEventName] [varchar](255) NOT NULL,
        [LastUpdatedOnGMT] [varchar](50) NOT NULL,
        [LastUpdatedBy] [nvarchar](255) NOT NULL,
        [IsProcessed] [char](1) NULL,

        PRIMARY KEY CLUSTERED ([Id] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
END

IF NOT EXISTS (SELECT * FROM sys.objects 
               WHERE object_id = OBJECT_ID(N'[dbo].[DF__Kovair_Ji__IsPro__5224328E]') 
                 AND type = 'D')
BEGIN
    ALTER TABLE [dbo].[Kovair_JileEventHistory] 
        ADD DEFAULT ('N') FOR [IsProcessed]
END

当我在不同的系统中执行此行时,如果我执行一次它工作正常但是在我第二次执行它时它给我一个错误如下。

Msg 1781, Level 16, State 1, Line 26
Column already has a DEFAULT bound to it.

Msg 1750, Level 16, State 0, Line 26
Could not create constraint. See previous errors.

但是,每当我在生成此脚本的系统中执行相同操作时,我都可以多次执行它而不会出现任何错误。

我觉得

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DF__Kovair_Ji__IsPro__5224328E]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[Kovair_JileEventHistory] ADD  DEFAULT ('N') FOR [IsProcessed]
END

在这行中 OBJECT_ID(N'[dbo].[DF__Kovair_Ji__IsPro__5224328E]') 是系统特定的部分。

有什么办法可以解决这个问题吗?

这是有缺陷的:

IF NOT EXISTS 
(
  SELECT * FROM sys.objects 
  WHERE object_id = OBJECT_ID(N'[dbo].[DF__Kovair_Ji__IsPro__5224328E]') 
  AND type = 'D'
)

有几个原因:

  1. 您让系统命名约束,这意味着每次您创建 table 时,系统都会给出一个新名称。您应该始终明确命名您的约束,以便可以使像这样的脚本更具预测性table,这样您就可以拥有一个合理的命名约定。

     ALTER TABLE dbo.tablename 
       ADD CONSTRAINT DF_SomethingSmarter
       DEFAULT('N') FOR IsProcessed;
    
  2. 你基本上只是在说“这个 table 这个名字有默认约束吗”但是你有 hard-coded 约束名称。由于不同的原因,这可能在 不同的 系统上表现不同 - 假设有另一列以 IsPro... 开头并且它 发生 得到 same quasi-random system-generated 约束名称。

  3. 如果您知道什么列和什么类型的约束,更安全(当然也更冗长)的检查是忽略约束名称并在 table + 列名称之后进行:

     IF NOT EXISTS 
     (
       SELECT 1 FROM sys.default_constraints AS dc
        WHERE parent_object_id = OBJECT_ID(N'dbo.Kovair_JileEventHistory')
        AND EXISTS
        (
           SELECT 1 FROM sys.columns AS c 
            WHERE c.object_id = dc.parent_object_id
              AND c.column_id = dc.parent_column_id
              AND c.name = N'IsProcessed')
        )
     )
     BEGIN
       -- now I know there is no default constraint
       -- on this column, no matter what it's named
     END
    

    我什至会主张更冗长的内容,因为在规模上 some of the metadata functions do not obey isolation semantics,这可能会出现问题,具体取决于更改的范围和整个脚本的可恢复性:

     IF NOT EXISTS 
     (
       SELECT 1 FROM sys.default_constraints AS dc
        INNER JOIN sys.tables AS t
          ON t.[object_id] = dc.parent_object_id
          AND t.name = N'Kovair_JileEventHistory'
          AND t.[schema_id] = 1
        WHERE EXISTS
        ...