Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

NOCHECK não desabilita referências de chave estrangeira


Eu usei os dois scripts a seguir para desabilitar chaves estrangeiras. Eu não os criei, encontrei-os em interwebs, mas eles funcionaram perfeitamente para mim nos últimos anos. Infelizmente não consigo mais encontrar a fonte deles.

reference_sp.sql é um procedimento armazenado que precisa ser criado antes da execução do outro script.

reference_run.sql é um script que gera um script para desabilitar/habilitar chaves estrangeiras.

Observe que é seguro executar o script fornecido aqui - ele não modifica o banco de dados (além de criar e excluir tabelas temporárias), apenas gera outro script que descarta e recria as chaves estrangeiras.

E agora os roteiros.

referências_sp.sql:
USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

/*********************************************************************************************
Copyright SQLServerNation.com
*  Author:  Tim Chapman
***********************************************************************************************/
CREATE PROCEDURE [dbo].[sp_ShowForeignKeyObjects]
AS
    SELECT 
        OBJECT_NAME(constid) AS ConstraintName,
        OBJECT_SCHEMA_NAME(fkeyid) + '.' + OBJECT_NAME(fkeyid) + '.' + COL_NAME(fkeyid, fkey) AS ForeignKeyObject,
        OBJECT_SCHEMA_NAME(rkeyid) + '.' + OBJECT_NAME(rkeyid) + '.' + COL_NAME(rkeyid, rkey) AS ReferenceKeyObject, 
        COL_NAME(fkeyid, fkey) AS ForeignKeyColumn,
        COL_NAME(rkeyid, rkey) AS ReferenceKeyColumn, 
        constid AS ConstraintID, 
        OBJECT_SCHEMA_NAME(fkeyid) + '.' + OBJECT_NAME(fkeyid) AS ForeignKeyTable,         
        fkeyid AS ForeignKeyID, 
        OBJECT_SCHEMA_NAME(rkeyid) + '.' + OBJECT_NAME(rkeyid) AS ReferenceKeyTable,
        rkeyid AS ReferenceKeyID,
        keyno AS KeySequenceNumber
    FROM 
        sysforeignkeys
    ORDER BY 
        OBJECT_NAME(rkeyid) ASC, COL_NAME(rkeyid, rkey)

GO

reference_run.sql:
IF OBJECT_ID('tempdb..#FK')>0
  DROP TABLE #FK

IF OBJECT_ID('tempdb..#Const')>0
  DROP TABLE #Const

CREATE TABLE #FK
(
  ConstraintName VARCHAR(255),
  ForeignKeyObject VARCHAR(255),
  ReferenceObject VARCHAR(255),
  ForeignKeyColumn VARCHAR(255),
  ReferenceKeyColumn VARCHAR(255),
  ConstraintID INT, 
  ForeignKeyTable VARCHAR(255),
  ForeignKeyID INT, 
  ReferenceKeyTable VARCHAR(255),
  ReferenceKeyID INT, 
  KeySequenceNumber SMALLINT
)

CREATE TABLE #Const
(
  ConstraintID INT, 
  FBuildField VARCHAR(2000) DEFAULT(''), 
  RBuildField VARCHAR(2000) DEFAULT(''), 
  CountField SMALLINT 
)

INSERT INTO #FK
EXEC sp_Showforeignkeyobjects

SET NOCOUNT ON
DECLARE  tempcursor
CURSOR
READ_ONLY
FOR 

  SELECT    
    f.ConstraintName ,
    f.ForeignKeyObject ,
    f.ReferenceObject ,
    f.ForeignKeyColumn ,
    f.ReferenceKeyColumn,
    f.ConstraintID , 
    f.ForeignKeyID , 
    f.ReferenceKeyID , 
    f.KeySequenceNumber, 
    f.ForeignKeyTable,
    f.ReferenceKeyTable 
  FROM #FK AS  f
    INNER JOIN 
    (
      SELECT ConstraintID, MAX(KeySequenceNumber) AS MaxSeq
      FROM #FK AS  k
      GROUP BY k.ConstraintID
    )b ON f.ConstraintID = b.ConstraintID AND f.KeySequenceNumber = b.MaxSeq

DECLARE 
  @ConstraintName VARCHAR(255),
  @ForeignKeyObject VARCHAR(255),
  @ReferenceObject VARCHAR(255),
  @ForeignKeyColumn VARCHAR(255),
  @ReferenceKeyColumn VARCHAR(255),
  @ConstraintID INT, 
  @ForeignKeyID INT, 
  @ReferenceKeyID INT, 
  @KeySequenceNumber SMALLINT, 
  @ForeignKeyTable VARCHAR(255),
  @ReferenceKeyTable VARCHAR(255)

OPEN tempcursor

  FETCH NEXT FROM tempCursor INTO 
  @ConstraintName ,
  @ForeignKeyObject ,
  @ReferenceObject ,
  @ForeignKeyColumn ,
  @ReferenceKeyColumn,
  @ConstraintID , 
  @ForeignKeyID , 
  @ReferenceKeyID, 
  @KeySequenceNumber,
  @ForeignKeyTable ,
  @ReferenceKeyTable 

WHILE (@@fetch_status <> -1)
BEGIN

  DECLARE  tempcursor2
  CURSOR
  READ_ONLY
  FOR 

    SELECT ConstraintID, ForeignKeyColumn, ReferenceKeyColumn, KeySequenceNumber 
    FROM #FK 
    WHERE ConstraintID = @ConstraintID

    ORDER BY ConstraintID, KeySequenceNumber ASC

  DECLARE @ConstraintID2 INT, @ForeignKeyColumn2 VARCHAR(255), @ReferenceKeyColumn2 VARCHAR(255), @KeySequenceNumber2 SMALLINT
  DECLARE @FKeyBuildField VARCHAR(1000), @RKeyBuildField VARCHAR(1000), @Cnt SMALLINT 

  OPEN tempcursor2

  SELECT @FKeyBuildField = '', @RKeyBuildField = '', @Cnt = 0

  FETCH NEXT FROM tempcursor2 INTO @ConstraintID2 , @ForeignKeyColumn2 , @ReferenceKeyColumn2 , @KeySequenceNumber2
  WHILE (@@fetch_status <> -1)
  BEGIN
    SET @Cnt = @Cnt + 1
    SELECT @FKeyBuildField = @FKeyBuildField  + ISNULL(@ForeignKeyColumn2,'')+ 
      CASE 
        WHEN @ForeignKeyColumn2 IS NULL THEN '' 
      ELSE  
        CASE WHEN @KeySequenceNumber = @KeySequenceNumber2 THEN '' ELSE ',' END
      END

    SELECT @RKeyBuildField = @RKeyBuildField  + ISNULL(@ReferenceKeyColumn2,'')+ 
      CASE 
        WHEN @ReferenceKeyColumn2 IS NULL THEN '' 
      ELSE  
        CASE WHEN @KeySequenceNumber = @KeySequenceNumber2 THEN '' ELSE ',' END
      END

    INSERT INTO #Const
    (   
      ConstraintID , 
      FBuildField , 
      RBuildField, 
      CountField  
    )
    VALUES
    (
      @ConstraintID, 
      @FKeyBuildField,
      @RKeyBuildField,
      @Cnt
    )

    FETCH NEXT FROM tempcursor2 INTO @ConstraintID2 , @ForeignKeyColumn2 , @ReferenceKeyColumn2 , @KeySequenceNumber2
  END
  CLOSE tempcursor2
  DEALLOCATE tempcursor2

  FETCH NEXT FROM tempCursor INTO 
  @ConstraintName ,
  @ForeignKeyObject ,
  @ReferenceObject ,
  @ForeignKeyColumn ,
  @ReferenceKeyColumn,
  @ConstraintID , 
  @ForeignKeyID , 
  @ReferenceKeyID , 
  @KeySequenceNumber ,
  @ForeignKeyTable ,
  @ReferenceKeyTable 
END

CLOSE tempcursor
DEALLOCATE tempcursor

SELECT 'ALTER TABLE ' + FKTable + ' DROP CONSTRAINT ' + OBJECT_NAME(a.ConstraintID) AS DropKeys,
'ALTER TABLE ' + FKTable + ' WITH NOCHECK ADD CONSTRAINT ' + OBJECT_NAME(a.ConstraintID) + ' FOREIGN KEY(' + FBuildField + ') REFERENCES ' + RKTable + '(' + RBuildField+')' AS BuildKeys
,*
FROM #Const a
JOIN
(
  SELECT ConstraintID, MAX(countfield) AS maxcount
  FROM #Const
  GROUP BY ConstraintID
) b ON a.ConstraintID = b.ConstraintID  AND a.countfield = b.maxcount
JOIN
(
SELECT DISTINCT constraintid, '[' + OBJECT_SCHEMA_NAME(foreignkeyid) + '].[' + OBJECT_NAME(foreignkeyid) + ']' AS FKTable, '[' + OBJECT_SCHEMA_NAME(referencekeyid) + '].[' + OBJECT_NAME(referencekeyid) + ']' AS RKTable FROM #fk
) c ON a.constraintid = c.constraintid

DROP TABLE #Const