Kısıtlama ile sütun nasıl bırakılır?


138

SQL Server 2008'de Varsayılan kısıtlaması olan bir sütun nasıl bırakılır?

Sorgum

alter table tbloffers
drop column checkin

Hata alıyorum

ALTER TABLE DROP COLUMN check-in işlemi bir veya daha fazla nesne bu sütuna eriştiği için başarısız oldu.

Birisi kısıtlamalı bir sütun bırakmak için sorgumu düzeltebilir mi?


bu hataya neden olan diğer tablolardan bu tabloya bazı referanslar olabilir.
Pankaj Upadhyay

Bunun üzerine tökezleyen yeni gelenler için, aşağıdaki cevabımı kontrol edin , eğer sizin için işe yarıyorsa, diğer bazı çözümlerden çok daha basittir.
BrainSlugs83

Sorum ve cevabımı burada
listeledim

Yanıtlar:


233

İlk önce problemli olanı bırakmalısınız DEFAULT constraint, bundan sonra sütunu bırakabilirsiniz

alter table tbloffers drop constraint [ConstraintName]
go

alter table tbloffers drop column checkin

Ancak hata başka nedenlerden de ortaya çıkabilir - örneğin, kullanıcı tanımlı işlev veya görünüm SCHEMABINDINGonlar için ayarlanmış seçenek.

UPD: Kısıtlama komut dosyasının tamamen otomatik olarak bırakılması:

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
Otomatik komut dosyası için teşekkürler. Tıkır tıkır çalışıyor!
kanadianDri3

Çok teşekkür ederim - çok zaman kazandın. Burada sorduğum soruyu
bağladım

130

Kısıtlama adını almak için önce ayrı bir sorgu çalıştırmak zorunda kalmadan bilinmeyen bir adla varsayılan bir kısıtlamayı bırakmanın başka bir yolu:

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ükemmel bir cevap, teşekkür ederim. Yine de, yukarıdaki yanıtı, düşürmeye karar vermeden önce ilk önce SELECTing ve teftiş alışkanlığından çıkardım.
noogrub

7
Gerçekten harika bir cevap. Kolaylık / gelecekteki kullanım için saklı bir prosedür gerçekleştirdim: pastebin.com/2CeXZDh2
Digs

Mükemmel cevap ama yine de bir kolona bağlı birden fazla kısıtlama olduğunda eksik yaklaşım. Döngü dahil @Digs 'post benzer bazı depolanan proc 5 yıldız cevap olabilir
YeinCM-Qva

27

Ayrıca sütunu ve kısıtlamalarını tek tek değil, tek bir deyimde bırakabilirsiniz.

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 

Bağımlı kontrol kısıtlamaları ve varsayılan kısıtlamaların adlarını arayacak ve bunları sütunla birlikte bırakacak bazı dinamik SQL aşağıdadır

(ancak yabancı anahtarlar, benzersiz ve birincil anahtar kısıtlamaları, hesaplanan sütunlar, dizinler gibi diğer olası sütun bağımlılıkları)

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

Bu, kısıtlamanın adını bilmenizi gerektirir. Tablo oluşturma sırasında adlandırılmamışsa, otomatik olarak oluşturulan bir ad alırlar.
Joey

1
@Joey - Adı bilmeden kısıtlamaları bırakmak için bir sözdizimi yoktur. DROP CONSTRAINT Dilbilgisini görmek zorunlu bir argümandır. Kısıtlamaları açıkça adlandırmazsanız, SQL Server'ın adına, örneğin marc'ın cevabına göre oluşturulan adı aramanız gerekir. Ancak bunu öğrendikten sonra, kısıtlamayı ve sütunu aynı anda bırakabilirsiniz.
Martin Smith

Güzel kod, birden fazla kısıtlamaları bir kerede bırakmam gerekiyordu, ama sütun değil. Alteriniz hile yaptı. Teşekkürler!!
htm11h

26

Bu sorguyla ilgili varsayılan kısıtlamayı burada bulabilirsiniz:

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

Bu, tablo ve sütun adının yanı sıra varsayılan kısıtlamanın adını verir.

Bu bilgilere sahip olduğunuzda, önce varsayılan kısıtlamayı bırakmanız gerekir:

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

ve sonra sütunu bırakabilirsiniz

ALTER TABLE dbo.YourTable DROP COLUMN YourColumn

2
Sırasıyla yapılması gerekmez. İkisini de aynı anda yapabilirsiniz.
Martin Smith

1
@MartinSmith: Tamam, harika - paylaştığın için teşekkürler! Bu olasılığın farkında değildim - her gün yeni bir şeyler öğreniyorsun! :-)
marc_s

Birisi lütfen bu iki ifadenin nasıl birleştirileceğine bir örnek verebilir mi? Şöyle bir şeye ihtiyacım var: ALTER TABLE table DROP CONSTRAINT DF_XY DROP COLUMN XYNe yazık ki bu ifadenin sözdizimi doğru değil
My-Name-Is

1
@ My-Name-Is: Martin'in cevabına bakarsanız, bu işi yapmak için iki komut arasına bir virgül koymanız gerekirDROP
marc_s

3

Aşağıdakiler benim için bir SQL Azure arka ucuna (SQL Server Management Studio kullanarak) karşı çalıştı, bu yüzden YMMV, ancak sizin için çalışıyorsa, diğer çözümlerden daha basittir.

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

1

Aynısını aldım:

ALTER TABLE DROP COLUMN, bir veya daha fazla nesne bu sütun iletisine eriştiği için başarısız oldu .

Sütunumun önce silinmesi gereken bir dizini vardı. Sys.indexes kullanmak hile yaptı:

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

Betiği SQL sunucu sürümüme biraz güncelledim

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

Her zaman yalnızca bir sütunun düşmesini önleyen varsayılan bir kısıtlama değildir ve bazen dizinler de kısıtlamayı bırakmanızı engelleyebilir. Bu yüzden bir sütuna herhangi bir indeks veya kısıtlama ve sonunda kendi kendine sütun bırakan bir prosedür yazdım.

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 = ''
    ;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.