Wie lösche ich alle Einschränkungen aus allen Tabellen?

30

Ich möchte alle Standardeinschränkungen, Prüfeinschränkungen, eindeutigen Einschränkungen, Primärschlüssel und Fremdschlüssel aus allen Tabellen in einer SQL Server-Datenbank löschen. Ich weiß, wie ich alle Einschränkungsnamen abrufen kann sys.objects, aber wie fülle ich das ALTER TABLETeil auf?

Aaron Bertrand
quelle
Was ist aus Neugier der Kontext einer solchen Anfrage? Ich frage mich, wie funktionale Abhängigkeiten behandelt werden (dh indizierte Ansichten, Kaskadenereignisse für FKs und UQs mit IGNORE_DUP_KEY = ON).
Solomon Rutzky
3
@srutzky Es wurde bei Stack Overflow gefragt, aber ich habe mich entschlossen, hier eine sauberere, kanonische Version zu erstellen. Auf jeden Fall handelt es sich um eine häufige Anforderung, die häufig Teil einer größeren Aufgabe zum Bereinigen einer Datenbank ist (erneutes Starten, Bereinigen von Objekten, die versehentlich in den Master eingefügt wurden usw.). Ich sehe keine Beeinträchtigung dieser funktionalen Abhängigkeiten durch das Löschen der Einschränkungen - in der Tat vermute ich, dass das größere Bild in den meisten Fällen auch die Tabellen beschneidet oder löscht. Wenn Sie zuerst die Einschränkungen löschen, ist dies möglich.
Aaron Bertrand

Antworten:

36

Sie können diese Informationen einfach ableiten, indem Sie sie sys.tables.object_id = sys.objects.parent_object_idfür diese Objekttypen verbinden.

DECLARE @sql NVARCHAR(MAX);
SET @sql = N'';

SELECT @sql = @sql + N'
  ALTER TABLE ' + QUOTENAME(s.name) + N'.'
  + QUOTENAME(t.name) + N' DROP CONSTRAINT '
  + QUOTENAME(c.name) + ';'
FROM sys.objects AS c
INNER JOIN sys.tables AS t
ON c.parent_object_id = t.[object_id]
INNER JOIN sys.schemas AS s 
ON t.[schema_id] = s.[schema_id]
WHERE c.[type] IN ('D','C','F','PK','UQ')
ORDER BY c.[type];

PRINT @sql;
--EXEC sys.sp_executesql @sql;

PRINTist nur zum Anschauen da - wenn Sie viele Einschränkungen haben, wird möglicherweise nicht das gesamte Skript angezeigt, da es auf 8 KB beschränkt ist. In diesen Fällen finden Sie in diesem Tipp weitere Möglichkeiten zum Überprüfen des Skripts vor dem Ausführen.

Wenn Sie mit der Ausgabe zufrieden sind, entfernen Sie das Kommentarzeichen EXEC.

Aaron Bertrand
quelle
3
Möglicherweise möchten Sie auch sicherstellen, dass Fremdschlüsseleinschränkungen vor Primärschlüsseln gelöscht werden. ORDER BY (CASE WHEN c.[type] IN ('PK', 'UQ') THEN 1 ELSE 0 END)
Daniel Hutmacher
1
@ Daniel guter Punkt, ORDER BY-Typ ist wahrscheinlich ausreichend, bis SQL Server neue Einschränkungstypen einführt.
Aaron Bertrand
6

Ich begann mit der akzeptierten Antwort und änderte die Struktur, um eine while-Schleife zu verwenden, anstatt die vollständige SQL-Anweisung in Dynamic SQL zu erstellen. Ich mag das aus mehreren Gründen besser.

Die Abfrage wird nicht in der großen Variablen @sql gespeichert. Diese Implementierung ermöglicht einen Druck für jede Einschränkung, die zu Protokollierungszwecken in der Ausgabe gelöscht wird. Die Ausführung schien in meinen Unit-Tests etwas schneller zu sein.

Set NoCount ON

Declare @schemaName varchar(200)
set @schemaName=''
Declare @constraintName varchar(200)
set @constraintName=''
Declare @tableName varchar(200)
set @tableName=''

While exists
(   
    SELECT c.name
    FROM sys.objects AS c
    INNER JOIN sys.tables AS t
    ON c.parent_object_id = t.[object_id]
    INNER JOIN sys.schemas AS s 
    ON t.[schema_id] = s.[schema_id]
    WHERE c.[type] IN ('D','C','F','PK','UQ')
    and t.[name] NOT IN ('__RefactorLog', 'sysdiagrams')
    and c.name > @constraintName
)

Begin   
    -- First get the Constraint
    SELECT 
        @constraintName=min(c.name)
    FROM sys.objects AS c
    INNER JOIN sys.tables AS t
    ON c.parent_object_id = t.[object_id]
    INNER JOIN sys.schemas AS s 
    ON t.[schema_id] = s.[schema_id]
    WHERE c.[type] IN ('D','C','F','PK','UQ')
    and t.[name] NOT IN ('__RefactorLog', 'sysdiagrams')
    and c.name > @constraintName

    -- Then select the Table and Schema associated to the current constraint
    SELECT 
        @tableName = t.name,
        @schemaName = s.name
    FROM sys.objects AS c
    INNER JOIN sys.tables AS t
    ON c.parent_object_id = t.[object_id]
    INNER JOIN sys.schemas AS s 
    ON t.[schema_id] = s.[schema_id]
    WHERE c.name = @constraintName

    -- Then Print to the output and drop the constraint
    Print 'Dropping constraint ' + @constraintName + '...'
    Exec('ALTER TABLE [' + @schemaName + N'].[' + @tableName + N'] DROP CONSTRAINT [' + @constraintName + ']')
End

Set NoCount OFF
yourbuddypal
quelle