Как удалить столбец с ограничением?
Как удалить столбец с ограничениями по умолчанию в SQL Server 2008?
Мой запрос
alter table tbloffers
drop column checkin
Я становлюсь ниже ошибки
Ошибка ALTER TABLE DROP COLUMN, потому что один или несколько объектов обращаются к этому столбцу.
Может ли кто-нибудь исправить мой запрос, чтобы удалить столбец с ограничениями?
Ответы
Ответ 1
Сначала вы должны отказаться от проблемного DEFAULT constraint
, после чего вы можете удалить столбец
alter table tbloffers drop constraint [ConstraintName]
go
alter table tbloffers drop column checkin
Но ошибка может возникнуть по другим причинам - например, пользовательская функция или представление с установленной опцией SCHEMABINDING
.
UPD:
Полностью автоматическое удаление ограничений script:
DECLARE @sql NVARCHAR(MAX)
WHILE 1=1
BEGIN
SELECT TOP 1 @sql = N'alter table tbloffers drop constraint ['+dc.NAME+N']'
from sys.default_constraints dc
JOIN sys.columns c
ON c.default_object_id = dc.object_id
WHERE
dc.parent_object_id = OBJECT_ID('tbloffers')
AND c.name = N'checkin'
IF @@ROWCOUNT = 0 BREAK
EXEC (@sql)
END
Ответ 2
Здесь другой способ сбросить ограничение по умолчанию с неизвестным именем без необходимости сначала запускать отдельный запрос, чтобы получить имя ограничения:
DECLARE @ConstraintName nvarchar(200)
SELECT @ConstraintName = Name FROM SYS.DEFAULT_CONSTRAINTS
WHERE PARENT_OBJECT_ID = OBJECT_ID('__TableName__')
AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns
WHERE NAME = N'__ColumnName__'
AND object_id = OBJECT_ID(N'__TableName__'))
IF @ConstraintName IS NOT NULL
EXEC('ALTER TABLE __TableName__ DROP CONSTRAINT ' + @ConstraintName)
Ответ 3
Найти ограничение по умолчанию с помощью этого запроса:
SELECT
df.name 'Constraint Name' ,
t.name 'Table Name',
c.NAME 'Column Name'
FROM sys.default_constraints df
INNER JOIN sys.tables t ON df.parent_object_id = t.object_id
INNER JOIN sys.columns c ON df.parent_object_id = c.object_id AND df.parent_column_id = c.column_id
Это дает вам имя ограничения по умолчанию, а также имя таблицы и столбца.
Когда у вас есть эта информация, вам нужно сначала сбросить ограничение по умолчанию:
ALTER TABLE dbo.YourTable
DROP CONSTRAINT name-of-the-default-constraint-here
а затем вы можете удалить столбец
ALTER TABLE dbo.YourTable DROP COLUMN YourColumn
Ответ 4
Вы также можете удалить столбец и его ограничения (-и) в одном выражении, а не отдельно.
CREATE TABLE #T
(
Col1 INT CONSTRAINT UQ UNIQUE CONSTRAINT CK CHECK (Col1 > 5),
Col2 INT
)
ALTER TABLE #T DROP CONSTRAINT UQ ,
CONSTRAINT CK,
COLUMN Col1
DROP TABLE #T
Некоторые динамические SQL, которые будут искать имена зависимых проверочных ограничений и ограничений по умолчанию и отбрасывать их вместе с столбцом ниже
(но не другие возможные зависимости столбцов, такие как внешние ключи, ограничения уникальных и первичных ключей, вычисленные столбцы, индексы)
CREATE TABLE [dbo].[TestTable]
(
A INT DEFAULT '1' CHECK (A=1),
B INT,
CHECK (A > B)
)
GO
DECLARE @TwoPartTableNameQuoted nvarchar(500) = '[dbo].[TestTable]',
@ColumnNameUnQuoted sysname = 'A',
@DynSQL NVARCHAR(MAX);
SELECT @DynSQL =
'ALTER TABLE ' + @TwoPartTableNameQuoted + ' DROP' +
ISNULL(' CONSTRAINT ' + QUOTENAME(OBJECT_NAME(c.default_object_id)) + ',','') +
ISNULL(check_constraints,'') +
' COLUMN ' + QUOTENAME(@ColumnNameUnQuoted)
FROM sys.columns c
CROSS APPLY (SELECT ' CONSTRAINT ' + QUOTENAME(OBJECT_NAME(referencing_id)) + ','
FROM sys.sql_expression_dependencies
WHERE referenced_id = c.object_id
AND referenced_minor_id = c.column_id
AND OBJECTPROPERTYEX(referencing_id, 'BaseType') = 'C'
FOR XML PATH('')) ck(check_constraints)
WHERE c.object_id = object_id(@TwoPartTableNameQuoted)
AND c.name = @ColumnNameUnQuoted;
PRINT @DynSQL;
EXEC (@DynSQL);
Ответ 5
Следующие действия работали для меня против бэкэнда SQL Azure (с использованием SQL Server Management Studio), поэтому YMMV, но если он работает для вас, он будет проще, чем другие решения.
ALTER TABLE MyTable
DROP CONSTRAINT FK_MyColumn
CONSTRAINT DK_MyColumn
-- etc...
COLUMN MyColumn
GO
Ответ 6
Я получил то же самое:
ALTER TABLE DROP COLUMN не удалось, так как один или несколько объектов получают доступ к этому сообщению столбца.
У моей колонки был индекс, который нужно было удалить первым. Используя sys.indexes сделал трюк:
DECLARE @sql VARCHAR(max)
SELECT @sql = 'DROP INDEX ' + idx.NAME + ' ON tblName'
FROM sys.indexes idx
INNER JOIN sys.tables tbl ON idx.object_id = tbl.object_id
INNER JOIN sys.index_columns idxCol ON idx.index_id = idxCol.index_id
INNER JOIN sys.columns col ON idxCol.column_id = col.column_id
WHERE idx.type <> 0
AND tbl.NAME = 'tblName'
AND col.NAME = 'colName'
EXEC sp_executeSql @sql
GO
ALTER TABLE tblName
DROP COLUMN colName
Ответ 7
Я немного обновил скрипт к моей версии сервера SQL
DECLARE @sql nvarchar(max)
SELECT @sql = 'ALTER TABLE 'table_name' DROP CONSTRAINT ' + df.NAME
FROM sys.default_constraints df
INNER JOIN sys.tables t ON df.parent_object_id = t.object_id
INNER JOIN sys.columns c ON df.parent_object_id = c.object_id AND df.parent_column_id = c.column_id
where t.name = 'table_name' and c.name = 'column_name'
EXEC sp_executeSql @sql
GO
ALTER TABLE table_name
DROP COLUMN column_name;
Ответ 8
Это не всегда ограничение по умолчанию, которое предотвращает удаление столбца, и иногда индексы также могут блокировать удаление ограничения. Поэтому я написал процедуру, которая удаляет любой индекс или ограничение для столбца, а сам столбец в конце.
IF OBJECT_ID ('ADM_delete_column', 'P') IS NOT NULL
DROP procedure ADM_delete_column;
GO
CREATE procedure ADM_delete_column
@table_name_in nvarchar(300)
, @column_name_in nvarchar(300)
AS
BEGIN
/* Author: Matthis ([email protected] at 2019.07.20)
License CC BY (creativecommons.org)
Desc: Administrative procedure that drops columns at MS SQL Server
- if there is an index or constraint on the column
that will be dropped in advice
=> input parameters are TABLE NAME and COLUMN NAME as STRING
*/
SET NOCOUNT ON
--drop index if exist (search first if there is a index on the column)
declare @idx_name VARCHAR(100)
SELECT top 1 @idx_name = i.name
from sys.tables t
join sys.columns c
on t.object_id = c.object_id
join sys.index_columns ic
on c.object_id = ic.object_id
and c.column_id = ic.column_id
join sys.indexes i
on i.object_id = ic.object_id
and i.index_id = ic.index_id
where t.name like @table_name_in
and c.name like @column_name_in
if @idx_name is not null
begin
print concat('DROP INDEX ', @idx_name, ' ON ', @table_name_in)
exec ('DROP INDEX ' + @idx_name + ' ON ' + @table_name_in)
end
--drop fk constraint if exist (search first if there is a constraint on the column)
declare @fk_name VARCHAR(100)
SELECT top 1 @fk_name = CONSTRAINT_NAME
from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
where TABLE_NAME like @table_name_in
and COLUMN_NAME like @column_name_in
if @fk_name is not null
begin
print concat('ALTER TABLE ', @table_name_in, ' DROP CONSTRAINT ', @fk_name)
exec ('ALTER TABLE ' + @table_name_in + ' DROP CONSTRAINT ' + @fk_name)
end
--drop column if exist
declare @column_name VARCHAR(100)
SELECT top 1 @column_name = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME like concat('%',@column_name_in,'%')
if @column_name is not null
begin
print concat('ALTER TABLE ', @table_name_in, ' DROP COLUMN ', @column_name)
exec ('ALTER TABLE ' + @table_name_in + ' DROP COLUMN ' + @column_name)
end
end;
GO
--to run the procedure use this execute and fill the parameters
execute ADM_delete_column
@table_name_in = ''
, @column_name_in = ''
;