2009-01-27 12 views
175

puedo eliminar una tabla si existe usando el siguiente código, pero no saben cómo hacer lo mismo con una restricción:¿Cómo elimino una restricción de clave externa solo si existe en el servidor sql?

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

También agrego la restricción de utilizar este código:

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

Respuesta

248
IF (OBJECT_ID('FK_TableName_TableName2', 'F') IS NOT NULL) 
BEGIN 
    ALTER TABLE dbo.TableName DROP CONSTRAINT FK_TableName_TableName2 
END 
+1

es la bit si existe, estoy realmente después ... lo siento. actualizaré mi pregunta para que quede más claro. – solrevdev

+0

Lo siento, John se perdió ese pedacito, actualizaré mi respuesta –

+2

Si está utilizando Llaves foráneas generadas por EF con puntos en el nombre, necesita poner corchetes alrededor de los nombres como este [dbo]. [FK_dbo.MyTable_Etc] –

7
ALTER TABLE [dbo].[TableName] 
    DROP CONSTRAINT FK_TableName_TableName2 
+2

Quizás ponga eso en un bloque 'TRY..CATCH'. – onedaywhen

+0

"... si existe en el servidor sql? ..." - ¿cómo verifica que exista esa restricción? – new2ios

13

La respuesta de James funciona bien si conoce el nombre de la restricción real. Lo difícil es que en los escenarios heredados y en otros escenarios del mundo real, no puede saber cómo se llama la restricción.

Si este es el caso corre el riesgo de crear restricciones duplicados, para evitar que puede utilizar:

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

Lo único que añadiría es incluir el nombre como filtro en la selección de sys.foreign_keys ya que podría haber varias claves foráneas en la tabla – Koenyn

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

Esto es mucho más sencilla que la actual propuesta de solución:

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

Si necesita eliminar otro tipo de restricción, estos son los códigos aplicables para pasar a la función OBJECT_ID() en el segundo param eter position:

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

También puede usar OBJECT_ID sin el segundo parámetro.

lista completa de los tipos here:

Tipo de Objeto:

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 

artículo se refiere a: SQL Server 2012 a través de 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

+1 Mucho más fácil de leer y mantener. – Askolein

+0

+1 Me ayudó a eliminar mi restricción 'DF' (use 'D'). –

+0

Lista completa de tipos [aquí] (http://technet.microsoft.com/en-us/library/ms190324.aspx) (es decir, esto funciona para [todo tipo de cosas] (http://stackoverflow.com)/a/7887033/1028230), no solo claves). – ruffin

1

Creo que esta será útil para usted ...

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) 

se eliminará restricción de clave externa basada en la tabla y columna específica.

0

Puede usar esas consultas para encontrar todos los FK para su tabla.

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

La respuesta aceptada sobre esta cuestión no parece funcionar para mí.Logré lo mismo con un método ligeramente diferente:

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 
Cuestiones relacionadas