ฉันจะวางข้อ จำกัด foreign key ได้อย่างไรหากมีอยู่ในเซิร์ฟเวอร์ sql


235

ฉันสามารถวางตารางหากมีอยู่โดยใช้รหัสต่อไปนี้ แต่ไม่ทราบว่าจะทำอย่างไรกับข้อ จำกัด :

IF EXISTS(SELECT 1 FROM sys.objects WHERE OBJECT_ID = OBJECT_ID(N'TableName') AND type = (N'U')) DROP TABLE TableName
go 

ฉันยังเพิ่มข้อ จำกัด โดยใช้รหัสนี้:

ALTER TABLE [dbo].[TableName] 
  WITH CHECK ADD CONSTRAINT [FK_TableName_TableName2] FOREIGN KEY([FK_Name])
    REFERENCES [dbo].[TableName2] ([ID])
go

คำตอบ:


321

วิธีแก้ปัญหาที่ง่ายกว่านั้นมีให้ในคำตอบของ Eric Isaacs อย่างไรก็ตามมันจะพบข้อ จำกัด ในตารางใด ๆ หากคุณต้องการกำหนดเป้าหมายข้อ จำกัด foreign key ในตารางที่ระบุให้ใช้สิ่งนี้:

IF EXISTS (SELECT * 
  FROM sys.foreign_keys 
   WHERE object_id = OBJECT_ID(N'dbo.FK_TableName_TableName2')
   AND parent_object_id = OBJECT_ID(N'dbo.TableName')
)
  ALTER TABLE [dbo.TableName] DROP CONSTRAINT [FK_TableName_TableName2]

1
มันเป็นบิตที่มีอยู่ถ้าฉันเป็นจริงหลังจาก .. ขอโทษ ฉันจะอัปเดตคำถามของฉันเพื่อให้ชัดเจนยิ่งขึ้น!
solrevdev

2
หากคุณกำลังใช้ Foreign Keys ที่สร้างโดย EF พร้อมจุดในชื่อคุณต้องใส่เครื่องหมายวงเล็บในชื่อเช่นนี้ [dbo] [FK_dbo.MyTable_Etc]
David Sopko

ใน MSSQL 2017 ดูเหมือนว่าตอนนี้คอลัมน์จะถูกเรียกconstraint_object_idแทนที่จะเป็นเพียงแค่object_id
codenamezero

1
มันใช้งานไม่ได้ OBJECT_ID ('[CONSTRAINT_NAME]', 'F') ในคีย์ต่างประเทศที่ฉันรู้ว่ามีอยู่และมันกลับมาเป็นโมฆะ
นักพัฒนาเมลเบิร์น

1
@MelbourneDeveloper คุณอาจต้องการคำนำหน้าสคีมาหากมีคีย์ต่างประเทศอยู่ในสคีมาที่ไม่ใช่ dbo ตัวอย่างเช่น IF (SELECT OBJECT_ID (N '[Schema]. [FK_Name]', N'F ')) ไม่ใช่ค่า NULL ฉันมีปัญหาที่คล้ายกันกับคุณ (วิธีแก้ปัญหาของคุณใช้ได้สำหรับฉันเช่นกัน) จากนั้นฉันได้รับการทำงานผ่านตัวอย่างนี้ ฉันใช้ SQL Server 2012
iokevins

318

นี่เป็นวิธีที่ง่ายกว่าโซลูชันที่เสนอในปัจจุบัน:

IF (OBJECT_ID('dbo.FK_ConstraintName', 'F') IS NOT NULL)
BEGIN
    ALTER TABLE dbo.TableName DROP CONSTRAINT FK_ConstraintName
END

หากคุณต้องการปล่อยข้อ จำกัด ประเภทอื่นรหัสเหล่านี้เป็นรหัสที่ใช้บังคับเพื่อส่งผ่านไปยังฟังก์ชัน OBJECT_ID () ในตำแหน่งพารามิเตอร์ที่สอง:

C = CHECK constraint
D = DEFAULT (constraint or stand-alone)
F = FOREIGN KEY constraint
PK = PRIMARY KEY constraint
UQ = UNIQUE constraint

คุณสามารถใช้ OBJECT_ID โดยไม่มีพารามิเตอร์ที่สอง

รายการประเภททั้งหมดที่นี่ :

ประเภทวัตถุ:

AF = Aggregate function (CLR)
C = CHECK constraint
D = DEFAULT (constraint or stand-alone)
F = FOREIGN KEY constraint
FN = SQL scalar function
FS = Assembly (CLR) scalar-function
FT = Assembly (CLR) table-valued function
IF = SQL inline table-valued function
IT = Internal table
P = SQL Stored Procedure
PC = Assembly (CLR) stored-procedure
PG = Plan guide
PK = PRIMARY KEY constraint
R = Rule (old-style, stand-alone)
RF = Replication-filter-procedure
S = System base table
SN = Synonym
SO = Sequence object

ใช้กับ: SQL Server 2012 ถึง SQL Server 2014

SQ = Service queue
TA = Assembly (CLR) DML trigger
TF = SQL table-valued-function
TR = SQL DML trigger
TT = Table type
U = Table (user-defined)
UQ = UNIQUE constraint
V = View
X = Extended stored procedure

1
รายการประเภททั้งหมดที่นี่ (นั่นคือมันใช้ได้กับทุกสิ่งไม่ใช่แค่ปุ่ม)
ruffin

2
รับเสรีภาพในการเพิ่มลิงค์และรายการประเภท
มิทช์ข้าวสาลี

10
ปรากฏว่าหากข้อ จำกัด ไม่ได้อยู่ใน dbo schema คุณต้องใส่ชื่อ schema ด้วย ตัวอย่างเช่น: OBJECT_ID ('MySchema.FK_MyConstraint', 'F')
Giles Smith

1
วิธีนี้อาจจะง่ายกว่า แต่วิธีอื่นนั้นดีกว่าสำหรับการค้นหาและลบข้อ จำกัด อย่างชัดเจนแม้กระทั่งข้อ จำกัด ที่ใช้ชื่อเดียวกันกับตาราง / schemas / ฐานข้อมูลที่ต่างกัน
CSS

1
ฉันเห็นปัญหาหนึ่งที่นี่มันไม่เคยตรวจสอบให้แน่ใจว่ามีอยู่ในตารางที่เราวางมี
sandeep rawat



14

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

หากเป็นกรณีนี้คุณเสี่ยงต่อการสร้างข้อ จำกัด ที่ซ้ำซ้อนเพื่อหลีกเลี่ยงการใช้:

create function fnGetForeignKeyName
(
    @ParentTableName nvarchar(255), 
    @ParentColumnName nvarchar(255),
    @ReferencedTableName nvarchar(255),
    @ReferencedColumnName nvarchar(255)
)
returns nvarchar(255)
as
begin 
    declare @name nvarchar(255)

    select @name = fk.name  from sys.foreign_key_columns fc
    join sys.columns pc on pc.column_id = parent_column_id and parent_object_id = pc.object_id
    join sys.columns rc on rc.column_id = referenced_column_id and referenced_object_id = rc.object_id 
    join sys.objects po on po.object_id = pc.object_id
    join sys.objects ro on ro.object_id = rc.object_id 
    join sys.foreign_keys fk on fk.object_id = fc.constraint_object_id
    where 
        po.object_id = object_id(@ParentTableName) and 
        ro.object_id = object_id(@ReferencedTableName) and
        pc.name = @ParentColumnName and 
        rc.name = @ReferencedColumnName

    return @name
end

go

declare @name nvarchar(255)
declare @sql nvarchar(4000)
-- hunt for the constraint name on 'Badges.BadgeReasonTypeId' table refs the 'BadgeReasonTypes.Id'
select @name = dbo.fnGetForeignKeyName('dbo.Badges', 'BadgeReasonTypeId', 'dbo.BadgeReasonTypes', 'Id')
-- if we find it, the name will not be null
if @name is not null 
begin 
    set @sql = 'alter table Badges drop constraint ' + replace(@name,']', ']]')
    exec (@sql)
end


3
Declare @FKeyRemoveQuery NVarchar(max)

IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.TableName'))

BEGIN
    SELECT @FKeyRemoveQuery='ALTER TABLE dbo.TableName DROP CONSTRAINT [' + LTRIM(RTRIM([name])) + ']'   
    FROM sys.foreign_keys
    WHERE parent_object_id = OBJECT_ID(N'dbo.TableName')

    EXECUTE Sp_executesql @FKeyRemoveQuery 

END

สิ่งเดียวที่พิเศษที่ฉันจะเพิ่มคือรวมชื่อเป็นตัวกรองในตัวเลือกจาก sys.foreign_keys เนื่องจากอาจมีคีย์ต่างประเทศหลายตัวบนโต๊ะ
Koenyn

1

ฉันคิดว่านี่จะเป็นประโยชน์กับคุณ ...

    DECLARE @ConstraintName nvarchar(200)
SELECT 
    @ConstraintName = KCU.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC 
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
    ON KCU.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG  
    AND KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
    AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
WHERE
    KCU.TABLE_NAME = 'TABLE_NAME' AND
    KCU.COLUMN_NAME = 'TABLE_COLUMN_NAME'
IF @ConstraintName IS NOT NULL EXEC('alter table TABLE_NAME drop  CONSTRAINT ' + @ConstraintName)

มันจะลบข้อ จำกัด คีย์ต่างประเทศตามตารางและคอลัมน์ที่เฉพาะเจาะจง


0

คุณสามารถใช้แบบสอบถามเหล่านี้เพื่อค้นหา FK ทั้งหมดสำหรับตารางของคุณ

Declare @SchemaName VarChar(200) = 'Schema Name'
Declare @TableName VarChar(200) = 'Table name'

-- Find FK in This table.
SELECT 
    'IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N''' + 
      '[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' + FK.name + ']' 
      + ''') AND parent_object_id = OBJECT_ID(N''' + 
      '[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' 
      + OBJECT_NAME(FK.parent_object_id) + ']' + ''')) ' +

    'ALTER TABLE ' +  OBJECT_SCHEMA_NAME(FK.parent_object_id) +
    '.[' + OBJECT_NAME(FK.parent_object_id) + 
    '] DROP CONSTRAINT ' + FK.name
    , S.name , O.name, OBJECT_NAME(FK.parent_object_id)
FROM sys.foreign_keys AS FK
INNER JOIN Sys.objects As O 
  ON (O.object_id = FK.parent_object_id )
INNER JOIN SYS.schemas AS S 
  ON (O.schema_id = S.schema_id)  
WHERE 
      O.name = @TableName
      And S.name = @SchemaName


-- Find the FKs in the tables in which this table is used
  SELECT 
    ' IF  EXISTS (SELECT * FROM sys.foreign_keys WHERE object_id = OBJECT_ID(N''' + 
      '[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' + FK.name + ']' 
      + ''') AND parent_object_id = OBJECT_ID(N''' + 
      '[' + OBJECT_SCHEMA_NAME(FK.parent_object_id) + '].[' 
      + OBJECT_NAME(FK.parent_object_id) + ']' + ''')) ' +

    ' ALTER TABLE ' +  OBJECT_SCHEMA_NAME(FK.parent_object_id) +
    '.[' + OBJECT_NAME(FK.parent_object_id) + 
    '] DROP CONSTRAINT ' + FK.name
    , S.name , O.name, OBJECT_NAME(FK.parent_object_id)
FROM sys.foreign_keys AS FK
INNER JOIN Sys.objects As O 
  ON (O.object_id = FK.referenced_object_id )
INNER JOIN SYS.schemas AS S 
  ON (O.schema_id = S.schema_id)  
WHERE 
      O.name = @TableName
      And S.name = @SchemaName 

0

คำตอบที่ยอมรับในคำถามนี้ดูเหมือนจะไม่เหมาะกับฉัน ฉันทำสิ่งเดียวกันด้วยวิธีที่แตกต่างกันเล็กน้อย:

IF (select object_id from sys.foreign_keys where [name] = 'FK_TableName_TableName2') IS NOT NULL
BEGIN
    ALTER TABLE dbo.TableName DROP CONSTRAINT FK_TableName_TableName2
END
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.