Làm thế nào để tôi bỏ một ràng buộc khóa ngoại chỉ khi nó tồn tại trong máy chủ sql?


235

Tôi có thể thả bảng nếu nó tồn tại bằng cách sử dụng đoạn mã sau nhưng không biết cách thực hiện tương tự với một ràng buộc:

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

Tôi cũng thêm các ràng buộc sử dụng mã này:

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

Câu trả lời:


321

Giải pháp đơn giản hơn được cung cấp trong câu trả lời của Eric Isaacs . Tuy nhiên, nó sẽ tìm thấy các ràng buộc trên bất kỳ bảng nào. Nếu bạn muốn nhắm mục tiêu một ràng buộc khóa ngoại trên một bảng cụ thể, hãy sử dụng:

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
Nếu nó tồn tại bit tôi thực sự sau .. xin lỗi. Tôi sẽ cập nhật câu hỏi của mình để nó rõ ràng hơn!
solrevdev

2
Nếu bạn đang sử dụng Khóa ngoại được tạo bởi EF có dấu chấm trong tên, bạn cần đặt dấu ngoặc quanh các tên như thế này [dbo]. [FK_dbo.MyTable_Etc]
David Sopko

Trong MSSQL 2017, có vẻ như cột hiện đang được gọi constraint_object_idthay vì chỉobject_id
codenamezero

1
Điều này không hoạt động. OBJECT_ID ('[CONSTRAINT_NAME]', 'F') trên khóa ngoại mà tôi biết tồn tại và nó trả về null.
Nhà phát triển Melbourne

1
@MelbourneDeveloper Bạn có thể cần tiền tố lược đồ, nếu khóa ngoại tồn tại trong lược đồ không phải là dbo. Ví dụ: IF (CHỌN OBRI_ID (N '[Lược đồ]. [FK_Name]', N'F ')) KHÔNG PHẢI LÀ NULL. Tôi đã có vấn đề tương tự với bạn (giải pháp của bạn cũng làm việc cho tôi), sau đó tôi đã làm cho nó hoạt động thông qua ví dụ này. Tôi đang chạy SQL Server 2012.
iokevins

318

Điều này đơn giản hơn nhiều so với giải pháp đề xuất hiện tại:

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

Nếu bạn cần loại bỏ một loại ràng buộc khác, đây là các mã áp dụng để chuyển vào hàm OBJECT_ID () ở vị trí tham số thứ hai:

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

Bạn cũng có thể sử dụng OBJECT_ID mà không cần tham số thứ hai.

Danh sách đầy đủ các loại ở đây :

Loại đối tượng:

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

Áp dụng cho: SQL Server 2012 đến 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
Danh sách đầy đủ các loại ở đây (có nghĩa là, loại này hoạt động cho tất cả các loại công cụ , không chỉ các phím).
ruffin

2
Lấy sự tự do của việc thêm liên kết và danh sách các loại.
Mitch Wheat

10
Có vẻ như nếu ràng buộc không có trong lược đồ dbo thì bạn cũng cần bao gồm tên lược đồ. Ví dụ: OBJECT_ID ('MySchema.FK_MyConstraint', 'F')
Giles Smith

1
Cách này có thể đơn giản hơn, nhưng cách khác tốt hơn cho việc tìm và loại bỏ rõ ràng các ràng buộc, thậm chí các ràng buộc có cùng tên được áp dụng cho các bảng / lược đồ / cơ sở dữ liệu khác nhau.
CSS

1
Tôi thấy một vấn đề ở đây, nó không bao giờ đảm bảo nếu thùng chứa nằm trên bàn nơi chúng ta đang thả chứa.
sandeep rawat

36

Trong SQL Server 2016, bạn có thể sử dụng DROP NẾU EXISTS:

CREATE TABLE t(id int primary key, 
               parentid int
                    constraint tpartnt foreign key references t(id))
GO
ALTER TABLE t
DROP CONSTRAINT IF EXISTS tpartnt
GO
DROP TABLE IF EXISTS t

Xem httpbl //


15
IF (OBJECT_ID('DF_Constraint') IS NOT NULL)
BEGIN
    ALTER TABLE [dbo].[tableName]
    DROP CONSTRAINT DF_Constraint
END

14

Câu trả lời của James chỉ hoạt động tốt nếu bạn biết tên của ràng buộc thực tế. Điều khó khăn là trong di sản và các tình huống thực tế khác, bạn có thể không biết ràng buộc được gọi là gì.

Nếu đây là trường hợp bạn có nguy cơ tạo các ràng buộc trùng lặp, để tránh bạn có thể sử dụng:

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

5
ALTER TABLE [dbo].[TableName]
    DROP CONSTRAINT FK_TableName_TableName2

5
Có lẽ đặt nó trong một TRY..CATCHkhối.
onedaywhen

"... Nếu nó tồn tại trong máy chủ sql? ..." - làm thế nào để bạn kiểm tra ràng buộc đó tồn tại?
new2ios

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

điều duy nhất tôi muốn thêm là bao gồm tên dưới dạng bộ lọc trong phần chọn từ sys.forign_keys vì có thể có nhiều khóa ngoại trên bảng
Koenyn

1

Tôi nghĩ rằng điều này sẽ hữu ích cho bạn ...

    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)

Nó sẽ xóa ràng buộc khóa ngoại dựa trên bảng và cột cụ thể.


0

Bạn có thể sử dụng các truy vấn đó để tìm tất cả FK cho bảng của mình.

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

Câu trả lời được chấp nhận cho câu hỏi này dường như không hiệu quả với tôi. Tôi đã đạt được điều tương tự với một phương pháp hơi khác:

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
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.