Jak usunąć wszystkie ograniczenia ze wszystkich tabel?

30

Chcę usunąć wszystkie ograniczenia domyślne, ograniczenia sprawdzające, ograniczenia unikalne, klucze podstawowe i klucze obce ze wszystkich tabel w bazie danych SQL Server. Wiem, jak uzyskać wszystkie nazwy ograniczeń sys.objects, ale jak wypełnić ALTER TABLEczęść?

Aaron Bertrand
źródło
Z ciekawości, jaki jest kontekst takiego żądania? Zastanawiam się, w jaki sposób rozwiązane są zależności funkcjonalne (tj. Widoki indeksowane, zdarzenia kaskadowe na FK i UQ, które miały IGNORE_DUP_KEY = ON).
Solomon Rutzky
3
@srutzky Zapytano o to na Stack Overflow, ale postanowiłem stworzyć tutaj czystszą, kanoniczną wersję. W każdym razie jest to częste żądanie, często będące częścią większego zadania czyszczenia bazy danych (rozpoczynanie od nowa, czyszczenie obiektów, które zostały omyłkowo wprowadzone do master itp.). Nie widzę wpływu na te funkcjonalne zależności po usunięciu ograniczeń - w rzeczywistości podejrzewam, że w większości przypadków większy obraz również obciąża lub upuszcza tabele. Najpierw pozwala na to ograniczenie.
Aaron Bertrand

Odpowiedzi:

36

Możesz łatwo uzyskać te informacje, łącząc sys.tables.object_id = sys.objects.parent_object_iddla tych typów obiektów.

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;

PRINTjest tylko dla oka - jeśli masz wiele ograniczeń, może nie wyświetlać całego skryptu, ponieważ jest ograniczony do 8K. W takich przypadkach zapoznaj się z tą wskazówką, aby poznać inne sposoby sprawdzania skryptu przed uruchomieniem.

Gdy będziesz zadowolony z wyników, odkomentuj EXEC.

Aaron Bertrand
źródło
3
Możesz także upewnić się, że ograniczenia kluczy obcych zostały usunięte przed kluczami podstawowymi; ORDER BY (CASE WHEN c.[type] IN ('PK', 'UQ') THEN 1 ELSE 0 END)
Daniel Hutmacher
1
@Daniel dobry punkt, typ ORDER BY prawdopodobnie wystarcza, dopóki SQL Server nie wprowadzi nowych typów ograniczeń.
Aaron Bertrand
6

Zacząłem od zaakceptowanej odpowiedzi i zmodyfikowałem strukturę tak, aby używała pętli while zamiast budować pełną instrukcję SQL w dynamicznym SQL. Lubię to lepiej z kilku powodów.

Zapytanie nie jest przechowywane w dużej zmiennej @sql. Ta implementacja pozwala na wydruk dla każdego ograniczenia, które jest usuwane do celów rejestrowania w danych wyjściowych. Wykonanie wydawało mi się trochę szybsze w moich testach jednostkowych.

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
twojabuddypal
źródło