Làm thế nào để thả cột với ràng buộc?


138

Làm cách nào để thả một cột có ràng buộc Mặc định trong SQL Server 2008?

Truy vấn của tôi là

alter table tbloffers
drop column checkin

Tôi nhận được lỗi dưới đây

ALTER TABLE DROP COLUMN checkin thất bại vì một hoặc nhiều đối tượng truy cập vào cột này.

Bất cứ ai có thể sửa truy vấn của tôi để thả một cột với ràng buộc?


có thể có một số tham chiếu đến bảng này từ các bảng khác gây ra lỗi này.
Pankaj Upadhyay

Đối với những người mới đến vấp phải điều này, hãy xem câu trả lời của tôi dưới đây , nếu nó hiệu quả với bạn, nó đơn giản hơn một số giải pháp khác.
BrainSlugs83

Tôi đã liệt kê câu hỏi và câu trả lời của mình ở đây
Akash Yellappa

Câu trả lời:


233

Trước tiên, bạn nên thả vấn đề DEFAULT constraint, sau đó bạn có thể thả cột

alter table tbloffers drop constraint [ConstraintName]
go

alter table tbloffers drop column checkin

Nhưng lỗi có thể xuất hiện từ các lý do khác - ví dụ: chức năng do người dùng xác định hoặc chế độ xem với SCHEMABINDINGtùy chọn được đặt cho chúng.

CẬP NHẬT: Hoàn toàn tự động loại bỏ tập lệnh ràng buộc:

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

1
Cảm ơn kịch bản tự động. Hoạt động như một lá bùa!
kanadianDri3 14/03/2016

Cảm ơn bạn rất nhiều - bạn đã tiết kiệm cho tôi rất nhiều thời gian. Tôi đã liên kết câu hỏi tôi đã hỏi ở đây
Akash Yellappa

130

Đây là một cách khác để loại bỏ một ràng buộc mặc định với một tên không xác định mà không cần phải chạy một truy vấn riêng để có được tên ràng buộc:

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)

Một câu trả lời tuyệt vời, cảm ơn bạn. Mặc dù vậy, tôi cũng đã đưa ra câu trả lời ở trên, từ thói quen CHỌN và kiểm tra cũ trước khi quyết định bỏ.
noogrub

7
Câu trả lời tuyệt vời thực sự. Tôi đã thực hiện một quy trình được lưu trữ từ đó để thuận tiện / sử dụng trong tương lai: pastebin.com/2CeXZDh2
Digs

Câu trả lời tuyệt vời nhưng vẫn thiếu cách tiếp cận khi có nhiều hơn một ràng buộc gắn liền với một cột. Một số Proc được lưu trữ tương tự như bài đăng của @Digs có vòng lặp bao gồm có thể là câu trả lời 5 sao
YeinCM-Qva

27

Bạn cũng có thể thả cột và (các) ràng buộc của nó trong một câu lệnh thay vì riêng lẻ.

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 

Một số SQL động sẽ tìm kiếm tên của các ràng buộc kiểm tra phụ thuộc và các ràng buộc mặc định và thả chúng cùng với cột bên dưới

(nhưng không phải là các phụ thuộc cột có thể khác như khóa ngoại, ràng buộc khóa chính và duy nhất, cột được tính toán, chỉ mục)

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); 

Điều này đòi hỏi bạn phải biết tên của các ràng buộc, mặc dù. Nếu chúng không được đặt tên trong quá trình tạo bảng, chúng sẽ có một tên được tạo tự động.
Joey

1
@Joey - Không có cú pháp để bỏ các ràng buộc mà không biết tên. Đó là một đối số bắt buộc để DROP CONSTRAINT xem ngữ pháp Nếu bạn không đặt tên rõ ràng cho các ràng buộc thì bạn sẽ phải tìm tên SQL Server được tạo cho nó, ví dụ như câu trả lời của marc. Nhưng khi phát hiện ra rằng bạn vẫn có thể bỏ các ràng buộc và cột cùng một lúc.
Martin Smith

Mã đẹp, tôi cần bỏ các ràng buộc mulitple cùng một lúc, nhưng không phải là cột. Thay đổi của bạn đã lừa Cảm ơn!!
htm11h

26

Tìm ràng buộc mặc định với truy vấn này tại đây:

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

Điều này cung cấp cho bạn tên của ràng buộc mặc định, cũng như tên bảng và cột.

Khi bạn có thông tin đó, trước tiên bạn cần bỏ ràng buộc mặc định:

ALTER TABLE dbo.YourTable
DROP CONSTRAINT name-of-the-default-constraint-here

và sau đó bạn có thể thả cột

ALTER TABLE dbo.YourTable DROP COLUMN YourColumn

2
Nó không phải được thực hiện tuần tự. Bạn có thể làm cả hai cùng một lúc.
Martin Smith

1
@MartinSmith: OK, tuyệt - cảm ơn vì đã chia sẻ! Tôi đã không nhận thức được khả năng này - bạn học được điều gì đó mới mỗi ngày! :-)
marc_s

Ai đó có thể vui lòng cung cấp một ví dụ cho cách kết hợp hai tuyên bố này. Tôi cần đôi khi như: ALTER TABLE table DROP CONSTRAINT DF_XY DROP COLUMN XYThật không may cú pháp của tuyên bố này không chính xác
Tên tôi-Là

1
@ My-Name-Is: nếu bạn xem câu trả lời của Martin, bạn cần đặt dấu phẩy giữa hai DROPlệnh để thực hiện công việc này
marc_s

3

Phần sau đây giúp tôi chống lại phần phụ trợ SQL Azure (sử dụng SQL Server Management Studio), vì vậy YMMV, nhưng, nếu nó hoạt động với bạn, nó đơn giản hơn các giải pháp khác.

ALTER TABLE MyTable
    DROP CONSTRAINT FK_MyColumn
    CONSTRAINT DK_MyColumn
    -- etc...
    COLUMN MyColumn
GO

1

Tôi đã nhận được cùng:

ALTER TABLE DROP COLUMN không thành công vì một hoặc nhiều đối tượng truy cập thông báo cột này .

Cột của tôi có một chỉ mục cần được xóa đầu tiên. Sử dụng sys.indexes đã thực hiện thủ thuật:

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

0

Tôi đã cập nhật tập lệnh một chút cho phiên bản máy chủ SQL của mình

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;


0

Không phải lúc nào cũng chỉ là một ràng buộc mặc định ngăn cản việc thả cột và đôi khi các chỉ mục cũng có thể chặn bạn khỏi việc ràng buộc. Vì vậy, tôi đã viết một thủ tục giảm bất kỳ chỉ mục hoặc ràng buộc nào trên một cột và cột tự nó ở cuối.

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 (matthis@online.ms 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 = ''
    ;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.