Bagaimana cara menjatuhkan kolom dengan kendala?

138

Bagaimana cara menjatuhkan kolom yang memiliki kendala Default di SQL Server 2008?

Kueri saya adalah

alter table tbloffers
drop column checkin

Saya mendapatkan kesalahan di bawah ini

ALTER TABLE DROP COLUMN checkin gagal karena satu atau lebih objek mengakses kolom ini.

Adakah yang bisa memperbaiki kueri saya untuk menjatuhkan kolom dengan kendala?

Robin Michael Poothurai
sumber
mungkin ada beberapa referensi ke tabel ini dari tabel lain yang menyebabkan kesalahan ini.
Pankaj Upadhyay
Untuk pendatang baru yang tersandung pada ini, lihat jawaban saya di bawah ini , jika itu bekerja untuk Anda, itu jauh lebih sederhana daripada beberapa solusi lainnya.
BrainSlugs83
Saya telah mendaftarkan pertanyaan dan jawaban saya di sini
Akash Yellappa

Jawaban:

233

Pertama, Anda harus menghapus yang bermasalah DEFAULT constraint, setelah itu Anda bisa menjatuhkan kolom

alter table tbloffers drop constraint [ConstraintName]
go

alter table tbloffers drop column checkin

Tetapi kesalahan mungkin muncul dari alasan lain - misalnya fungsi yang ditentukan pengguna atau tampilan dengan SCHEMABINDINGopsi yang ditetapkan untuk mereka.

UPD: Script kendala menjatuhkan yang sepenuhnya otomatis:

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
Oleg Dok
sumber
1
Terima kasih untuk skrip otomatis. Bekerja seperti pesona!
kanadianDri3
Terima kasih banyak - Anda menyelamatkan saya banyak waktu. Saya telah menautkan pertanyaan yang saya tanyakan di sini
Akash Yellappa
130

Berikut cara lain untuk menjatuhkan batasan default dengan nama yang tidak dikenal tanpa harus terlebih dahulu menjalankan kueri terpisah untuk mendapatkan nama kendala:

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)
Chris Halcrow
sumber
Jawaban yang luar biasa, terima kasih. Saya memilih jawaban di atas juga, meskipun, hanya dari kebiasaan lama yang pilih-pilih dan memeriksa dulu sebelum memutuskan untuk berhenti.
noogrub
7
Jawaban yang bagus. Saya membuat prosedur tersimpan untuk kenyamanan / penggunaan di masa mendatang: pastebin.com/2CeXZDh2
Digs
Jawaban yang sangat bagus tetapi pendekatan yang masih hilang ketika ada lebih dari satu kendala terikat pada kolom. Beberapa proc yang disimpan mirip dengan postingan @Digs dengan loop sudah termasuk jawaban 5 bintang
YeinCM-Qva
27

Anda juga dapat menjatuhkan kolom dan batasannya dalam satu pernyataan, bukan satu per satu.

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 

Beberapa SQL dinamis yang akan mencari nama-nama kendala pemeriksaan dependen dan kendala default dan letakkan bersama kolom di bawah ini

(tetapi tidak dependensi kolom lain yang mungkin seperti kunci asing, batasan kunci primer dan unik, kolom yang dihitung, indeks)

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); 
Martin Smith
sumber
Ini mengharuskan Anda untuk mengetahui nama batasannya. Jika mereka tidak dinamai selama pembuatan tabel, mereka mendapatkan nama yang dibuat secara otomatis.
Joey
1
@ Joey - Tidak ada sintaks untuk menjatuhkan batasan tanpa mengetahui namanya. Ini adalah argumen yang diperlukan untuk DROP CONSTRAINT melihat tata bahasa Jika Anda tidak menyebutkan kendala secara eksplisit maka Anda harus mencari nama SQL Server yang dihasilkan untuk itu misalnya sesuai jawaban marc. Tetapi setelah mengetahui hal itu, Anda masih bisa menghilangkan kendala dan kolom pada saat yang sama.
Martin Smith
Kode yang bagus, saya harus menghapus batasan mulitple sekaligus, tetapi tidak pada kolom. Alter Anda melakukan trik. Terima kasih!!
htm11h
26

Temukan batasan default dengan kueri ini di sini:

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

Ini memberi Anda nama batasan default, serta nama tabel dan kolom.

Ketika Anda memiliki informasi itu, Anda harus terlebih dahulu menjatuhkan batasan default:

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

dan kemudian Anda bisa menjatuhkan kolom

ALTER TABLE dbo.YourTable DROP COLUMN YourColumn
marc_s
sumber
2
Itu tidak harus dilakukan secara berurutan. Anda dapat melakukan keduanya sekaligus.
Martin Smith
1
@ MartinSmith: Oke, bagus - terima kasih sudah berbagi! Saya tidak mengetahui kemungkinan ini - Anda belajar sesuatu yang baru setiap hari! :-)
marc_s
Dapatkah seseorang tolong berikan contoh bagaimana menggabungkan kedua pernyataan ini. Saya perlu sesuatu seperti: ALTER TABLE table DROP CONSTRAINT DF_XY DROP COLUMN XYSayangnya sintaks dari pernyataan ini tidak benar
My-Name-Is
1
@ My-Name-Is: jika Anda memeriksa jawaban Martin, Anda harus meletakkan koma di antara dua DROPperintah untuk membuat pekerjaan ini
marc_s
3

Berikut ini bekerja untuk saya terhadap backend SQL Azure (menggunakan SQL Server Management Studio), jadi YMMV, tetapi, jika bekerja untuk Anda, itu waaaaay lebih sederhana daripada solusi lainnya.

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

Saya mendapat hal yang sama:

ALTER TABLE DROP COLUMN gagal karena satu atau lebih objek mengakses pesan kolom ini .

Kolom saya memiliki indeks yang perlu dihapus terlebih dahulu. Menggunakan sys.indexes berhasil:

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
Ewald Stieger
sumber
0

Saya telah memperbarui skrip sedikit ke versi SQL server saya

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;
Łukasz Dawid Wątor
sumber
0

Ini tidak selalu hanya kendala default yang mencegah dari menjatuhkan kolom dan kadang-kadang indeks juga dapat memblokir Anda dari menjatuhkan kendala. Jadi saya menulis prosedur yang menjatuhkan indeks atau batasan pada kolom dan kolom itu sendiri di akhir.

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 = ''
    ;
DataMatini
sumber