Wie lösche ich eine Fremdschlüsseleinschränkung nur, wenn sie auf einem SQL Server vorhanden ist?

235

Ich kann eine Tabelle löschen, wenn sie mit dem folgenden Code vorhanden ist, weiß aber nicht, wie ich dasselbe mit einer Einschränkung tun soll:

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

Ich füge auch die Einschränkung mit diesem Code hinzu:

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

Antworten:

321

Die einfachere Lösung findet sich in der Antwort von Eric Isaacs . Es werden jedoch Einschränkungen für jede Tabelle gefunden. Wenn Sie eine Fremdschlüsseleinschränkung für eine bestimmte Tabelle festlegen möchten, verwenden Sie Folgendes:

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.
quelle
1
Es ist das Wenn existiert Bit, nach dem ich wirklich bin. Entschuldigung. Ich werde meine Frage aktualisieren, damit es klarer ist!
Solrevdev
2
Wenn Sie EF-generierte Fremdschlüssel mit Punkten im Namen verwenden, müssen Sie die Namen wie folgt in Klammern setzen [dbo]. [FK_dbo.MyTable_Etc]
David Sopko
In MSSQL 2017 sieht es so aus, als würde die Spalte jetzt aufgerufen constraint_object_idanstatt nurobject_id
codenamezero
1
Das funktioniert nicht. OBJECT_ID ('[CONSTRAINT_NAME]', 'F') für einen Fremdschlüssel, von dem ich weiß, dass er existiert, und er hat null zurückgegeben.
Melbourne Entwickler
1
@MelbourneDeveloper Möglicherweise benötigen Sie das Schema-Präfix, wenn der Fremdschlüssel in einem Nicht-Dbo-Schema vorhanden ist. Zum Beispiel ist IF (SELECT OBJECT_ID (N '[Schema]. [FK_Name]', N'F ')) NICHT NULL. Ich hatte ähnliche Probleme wie Sie (Ihre Lösung hat auch bei mir funktioniert), dann habe ich sie über dieses Beispiel zum Laufen gebracht. Ich verwende SQL Server 2012.
Iokevins
318

Dies ist viel einfacher als die derzeit vorgeschlagene Lösung:

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

Wenn Sie eine andere Art von Einschränkung löschen müssen, sind dies die zutreffenden Codes, die an der zweiten Parameterposition an die Funktion OBJECT_ID () übergeben werden:

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

Sie können OBJECT_ID auch ohne den zweiten Parameter verwenden.

Vollständige Liste der Typen hier :

Objekttyp:

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

Gilt für: SQL Server 2012 bis 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
quelle
1
Vollständige Liste der Typen hier (das heißt, dies funktioniert für alle möglichen Dinge , nicht nur für Schlüssel).
Ruffin
2
Hat sich die Freiheit genommen, einen Link und eine Liste von Typen hinzuzufügen.
Mitch Wheat
10
Wenn die Einschränkung nicht im dbo-Schema enthalten ist, müssen Sie anscheinend auch den Schemanamen angeben. Beispiel: OBJECT_ID ('MySchema.FK_MyConstraint', 'F')
Giles Smith
1
Dieser Weg mag einfacher sein, aber der andere Weg ist besser, um Einschränkungen explizit zu finden und zu entfernen, selbst Einschränkungen mit demselben Namen, die auf verschiedene Tabellen / Schemas / Datenbanken angewendet werden.
CSS
1
Ich sehe hier ein Problem, bei dem nie sichergestellt wird, ob sich das Contain auf dem Tisch befindet, auf dem das Contain abgelegt wird.
Sandeep Rawat
15
IF (OBJECT_ID('DF_Constraint') IS NOT NULL)
BEGIN
    ALTER TABLE [dbo].[tableName]
    DROP CONSTRAINT DF_Constraint
END
DevDave
quelle
14

James 'Antwort funktioniert einwandfrei, wenn Sie den Namen der tatsächlichen Einschränkung kennen. Das Schwierige ist, dass Sie in Legacy- und anderen realen Szenarien möglicherweise nicht wissen, wie die Einschränkung heißt.

Wenn dies der Fall ist, besteht die Gefahr, dass Sie doppelte Einschränkungen erstellen. Um dies zu vermeiden, können Sie Folgendes verwenden:

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 Safran
quelle
5
ALTER TABLE [dbo].[TableName]
    DROP CONSTRAINT FK_TableName_TableName2
Mitch Wheat
quelle
5
Vielleicht setzen Sie das in einen TRY..CATCHBlock.
Tag, wenn
"... wenn es in SQL Server existiert? ..." - wie überprüfen Sie, ob die Einschränkung existiert?
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
quelle
Das einzige, was ich hinzufügen möchte, ist, den Namen als Filter in die Auswahl von sys.foreign_keys aufzunehmen, da möglicherweise mehrere Fremdschlüssel auf dem Tisch liegen
Koenyn,
1

Ich denke, das wird dir helfen ...

    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)

Die Fremdschlüsseleinschränkung wird basierend auf einer bestimmten Tabelle und Spalte gelöscht.

Samir Savasani
quelle
0

Mit diesen Abfragen können Sie alle FKs für Ihre Tabelle finden.

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
quelle
0

Die akzeptierte Antwort auf diese Frage scheint für mich nicht zu funktionieren. Ich habe dasselbe mit einer etwas anderen Methode erreicht:

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
Melbourne Entwickler
quelle