จะวางคอลัมน์ด้วยข้อ จำกัด ได้อย่างไร


138

วิธีการวางคอลัมน์ที่มีข้อ จำกัด เริ่มต้นใน SQL Server 2008

คำถามของฉันคือ

alter table tbloffers
drop column checkin

ฉันพบข้อผิดพลาดด้านล่าง

การเปลี่ยนแปลงตารางคอลัมน์เช็คอินล้มเหลวเนื่องจากวัตถุหนึ่งรายการขึ้นไปเข้าถึงคอลัมน์นี้

ทุกคนสามารถแก้ไขแบบสอบถามของฉันเพื่อวางคอลัมน์ที่มีข้อ จำกัด ได้หรือไม่


อาจมีการอ้างอิงถึงตารางนี้จากตารางอื่นซึ่งทำให้เกิดข้อผิดพลาดนี้
Pankaj Upadhyay

สำหรับผู้มาใหม่ที่สะดุดกับสิ่งนี้ลองดูคำตอบของฉันด้านล่างถ้ามันเหมาะกับคุณมันง่ายกว่าวิธีอื่น ๆ
BrainSlugs83

ฉันได้เขียนคำถามและคำตอบไว้ที่นี่แล้ว
Akash Yellappa

คำตอบ:


233

ก่อนอื่นคุณควรทิ้งปัญหาDEFAULT constraintไว้หลังจากนั้นคุณสามารถดร็อปคอลัมน์ได้

alter table tbloffers drop constraint [ConstraintName]
go

alter table tbloffers drop column checkin

แต่ข้อผิดพลาดอาจปรากฏขึ้นจากเหตุผลอื่น ๆ - ตัวอย่างเช่นฟังก์ชั่นที่ผู้ใช้กำหนดหรือดูด้วยSCHEMABINDINGตัวเลือกที่กำหนดไว้สำหรับพวกเขา

UPD: สคริปต์การ จำกัด โดยอัตโนมัติสมบูรณ์ลดลง:

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
ขอบคุณสำหรับสคริปต์อัตโนมัติ ทำงานเหมือนจับใจ!
kanadianDri3

ขอบคุณมาก - คุณช่วยฉันได้มากเวลา ฉันเชื่อมโยงคำถามที่ฉันถามไปที่นี่แล้ว
Akash Yellappa

130

นี่เป็นอีกวิธีในการวางข้อ จำกัด เริ่มต้นด้วยชื่อที่ไม่รู้จักโดยไม่ต้องเรียกใช้แบบสอบถามแยกต่างหากเพื่อรับชื่อข้อ จำกัด ก่อน:

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)

คำตอบที่ยอดเยี่ยมขอบคุณ ฉันตอบคำถามข้างต้นด้วยเช่นกัน แต่เพิ่งเลิกนิสัยเก่า ๆ ที่มีการเลือกและตรวจสอบก่อนที่จะตัดสินใจดรอป
noogrub

7
คำตอบที่ดีแน่นอน ฉันทำขั้นตอนการจัดเก็บออกมาเพื่อความสะดวกในการใช้งาน / ในอนาคต: pastebin.com/2CeXZDh2
Digs

คำตอบที่ดี แต่ก็ยังขาดวิธีเมื่อมีข้อ จำกัด มากกว่าหนึ่งข้อผูกติดอยู่กับคอลัมน์ บาง proc ที่เก็บไว้คล้ายกับ @Digs 'โพสต์พร้อมวงรวมอาจเป็น 5 ดาวคำตอบ
YeinCM-Qva

27

นอกจากนี้คุณยังสามารถวางคอลัมน์และข้อ จำกัด ลงในคำสั่งเดียวแทนที่จะเป็นรายบุคคล

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

สิ่งนี้กำหนดให้คุณต้องทราบชื่อของข้อ จำกัด หากพวกเขาไม่ได้รับการตั้งชื่อในระหว่างการสร้างตารางพวกเขาจะได้รับชื่อที่สร้างขึ้นโดยอัตโนมัติ
Joey

1
@Joey - ไม่มีไวยากรณ์ในการส่งข้อ จำกัด โดยไม่ทราบชื่อ มันเป็นอาร์กิวเมนต์ที่จำเป็นต้องใช้เพื่อDROP CONSTRAINT ดูไวยากรณ์หากคุณไม่ได้ตั้งชื่อข้อ จำกัด อย่างชัดเจนจากนั้นคุณจะต้องค้นหาชื่อ SQL Server ที่สร้างขึ้นสำหรับมันเช่นตามคำตอบของมาร์ค แต่เมื่อพบว่าคุณยังสามารถทิ้งข้อ จำกัด และคอลัมน์ได้ในเวลาเดียวกัน
Martin Smith

โค้ดที่ดีฉันต้องวางข้อ จำกัด แบบหลายจุดพร้อมกัน แต่ไม่ใช่คอลัมน์ การเปลี่ยนแปลงของคุณทำเคล็ดลับ ขอบคุณ !!
htm11h

26

ค้นหาข้อ จำกัด เริ่มต้นด้วยข้อความค้นหานี้ที่นี่:

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

2
ไม่จำเป็นต้องทำตามลำดับ คุณสามารถทำได้ทั้งสองอย่างในเวลาเดียวกัน
Martin Smith

1
@MartinSmith: ตกลงยอดเยี่ยม - ขอบคุณสำหรับการแบ่งปัน! ฉันไม่ได้ตระหนักถึงความเป็นไปได้นี้ - คุณเรียนรู้สิ่งใหม่ทุกวัน! :-)
marc_s

ใครช่วยกรุณาให้ตัวอย่างสำหรับวิธีการรวมสองคำสั่งนี้ ฉันต้องการ somethink เช่น: ALTER TABLE table DROP CONSTRAINT DF_XY DROP COLUMN XYขออภัยไวยากรณ์ของคำสั่งนี้ไม่ถูกต้อง
My-Name-Is

1
@ My-Name-Is: หากคุณตรวจสอบคำตอบของ Martin คุณจำเป็นต้องใส่เครื่องหมายจุลภาคระหว่างสองDROPคำสั่งในการทำงานนี้
marc_s

3

ต่อไปนี้ใช้งานได้สำหรับฉันกับแบ็กเอนด์ SQL Azure (โดยใช้ SQL Server Management Studio) ดังนั้น YMMV แต่ถ้ามันเหมาะกับคุณมัน waaaaay ง่ายกว่าโซลูชันอื่น ๆ

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

1

ฉันได้เหมือนกัน:

เปลี่ยนตาราง 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

0

ฉันได้อัปเดตสคริปต์เป็นเวอร์ชันเซิร์ฟเวอร์ 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;

0

ไม่ใช่ข้อ จำกัด เริ่มต้นเสมอที่ป้องกันไม่ให้วางคอลัมน์และบางครั้งดัชนีก็สามารถบล็อกคุณจากการปล่อยข้อ จำกัด ได้ ดังนั้นฉันจึงเขียนโพรซีเดอร์ที่ดร็อปดัชนีหรือข้อ จำกัด ใด ๆ ลงบนคอลัมน์และคอลัมน์นั้นจะเป็นตัวเองในตอนท้าย

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 = ''
    ;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.