Bagaimana cara menjatuhkan batasan kunci asing hanya jika ada di server sql?

235

Saya bisa menjatuhkan tabel jika ada menggunakan kode berikut tetapi tidak tahu bagaimana melakukan hal yang sama dengan kendala:

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

Saya juga menambahkan batasan menggunakan kode ini:

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

Jawaban:

321

Solusi yang lebih sederhana disediakan dalam jawaban Eric Isaacs . Namun, itu akan menemukan kendala pada tabel apa pun. Jika Anda ingin menargetkan batasan kunci asing pada tabel tertentu, gunakan ini:

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]
James L.
sumber
1
itu jika ada sedikit saya benar-benar setelah .. maaf. saya akan memperbarui pertanyaan saya jadi lebih jelas!
solrevdev
2
Jika Anda menggunakan Kunci Luar Negeri yang dihasilkan EF dengan titik-titik pada nama, Anda perlu menempatkan tanda kurung di sekitar nama-nama seperti ini [dbo]. [FK_dbo.MyTable_Etc]
David Sopko
Dalam MSSQL 2017, sepertinya kolom sekarang memanggil constraint_object_idbukan hanyaobject_id
codenamezero
1
Ini tidak berfungsi. OBJECT_ID ('[CONSTRAINT_NAME]', 'F') pada kunci asing yang saya tahu ada, dan mengembalikan nol.
Pengembang Melbourne
1
@MelbourneDeveloper Anda mungkin memerlukan awalan skema, jika kunci asing ada dalam skema non-dbo. Misalnya, JIKA (PILIH OBJECT_ID (N '[Skema]. [FK_Name]', N'F ')) BUKAN NULL. Saya memiliki masalah yang serupa dengan Anda (solusi Anda juga berhasil untuk saya), lalu saya membuatnya bekerja melalui contoh ini. Saya menjalankan SQL Server 2012.
iokevins
318

Ini jauh lebih sederhana daripada solusi yang diusulkan saat ini:

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

Jika Anda perlu menghapus jenis kendala lain, ini adalah kode yang berlaku untuk masuk ke fungsi OBJECT_ID () di posisi parameter kedua:

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

Anda juga dapat menggunakan OBJECT_ID tanpa parameter kedua.

Daftar lengkap jenis di sini :

Jenis objek:

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

Berlaku untuk: SQL Server 2012 melalui 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
Eric Isaacs
sumber
1
Daftar lengkap jenis di sini (yaitu, ini berfungsi untuk semua jenis barang , bukan hanya kunci).
ruffin
2
Mengambil kebebasan menambahkan tautan dan daftar jenis.
Mitch Wheat
10
Tampaknya jika kendala tidak ada dalam skema dbo maka Anda juga perlu memasukkan nama skema. Contoh: OBJECT_ID ('MySchema.FK_MyConstraint', 'F')
Giles Smith
1
Cara ini mungkin lebih sederhana, tetapi cara lain lebih baik untuk secara eksplisit menemukan dan menghapus kendala, bahkan kendala dengan nama yang sama diterapkan pada tabel / skema / database yang berbeda.
CSS
1
Saya melihat satu masalah di sini tidak pernah memastikan apakah isinya ada di meja tempat kita menjatuhkan isinya.
sandeep rawat
15
IF (OBJECT_ID('DF_Constraint') IS NOT NULL)
BEGIN
    ALTER TABLE [dbo].[tableName]
    DROP CONSTRAINT DF_Constraint
END
DevDave
sumber
14

Jawaban James bekerja dengan baik jika Anda tahu nama kendala yang sebenarnya. Yang sulit adalah bahwa dalam skenario warisan dan dunia nyata lainnya Anda mungkin tidak tahu apa kendala yang disebut.

Jika ini adalah kasus Anda berisiko membuat duplikat kendala, untuk menghindari Anda dapat menggunakan:

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
Sam Saffron
sumber
5
ALTER TABLE [dbo].[TableName]
    DROP CONSTRAINT FK_TableName_TableName2
Mitch Wheat
sumber
5
Mungkin meletakkannya di TRY..CATCHblok.
onedaywhen
"... jika ada di server sql? ..." - bagaimana Anda memeriksa batasan yang ada?
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
Rajalingam
sumber
Satu-satunya hal tambahan yang akan saya tambahkan adalah memasukkan nama sebagai filter dalam pilih dari sys.foreign_keys karena mungkin ada beberapa kunci asing di atas meja
Koenyn
1

Saya pikir ini akan membantu Anda ...

    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)

Ini akan menghapus batasan kunci asing berdasarkan tabel dan kolom tertentu.

Samir Savasani
sumber
0

Anda bisa menggunakan kueri itu untuk menemukan semua FK untuk tabel Anda.

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 
Ardalan Shahgholi
sumber
0

Jawaban yang diterima untuk pertanyaan ini sepertinya tidak berhasil untuk saya. Saya mencapai hal yang sama dengan metode yang sedikit berbeda:

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
Pengembang Melbourne
sumber