У меня есть таблица, как показано ниже, со столбцом значений по умолчанию как [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'
)
По нескольким причинам:
Вы позволяете системе назвать ограничение, что означает, что каждый раз, когда вы создаете таблицу, эта система будет придумывать новое имя. Вы всегда должны явно называть свои ограничения, чтобы такие сценарии можно было сделать более предсказуемыми и чтобы у вас было разумное соглашение об именах.
ALTER TABLE dbo.tablename
ADD CONSTRAINT DF_SomethingSmarter
DEFAULT('N') FOR IsProcessed;
Вы в основном просто говорите: «Есть ли ограничение по умолчанию для этой таблицы с этим именем», но вы жестко закодировали имя ограничения. Возможно, это может вести себя по-другому в системе другой по другой причине — скажем, есть еще один столбец, начинающийся с IsPro...
, и это бывает, чтобы получить псевдослучайное имя ограничения, сгенерированное системой такой же.
Если вы знаете, какой столбец и какой тип ограничения, гораздо более безопасная (и, по общему признанию, более подробная) проверка состоит в том, чтобы игнорировать имя ограничения и идти после имени таблицы + столбца:
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
Я бы даже предложил что-то более подробное, поскольку в масштабе некоторые функции метаданных не подчиняются семантике изоляции, что может быть проблематично в зависимости от области изменения и возможности восстановления всего скрипта:
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
...