2010-10-02 11 views
22

Mam tabeli o nazwie PX_Child, który ma klucz obcy na PX_Parent. Chciałbym tymczasowo wyłączyć to ograniczenie FK, aby móc skrócić PX_Parent. Nie jestem pewien, jak to się stanie.Wyłączenie ograniczenia klucza obcego, nadal nie można obciąć tabeli? (SQL Server 2005)

Próbowałem tych poleceń

ALTER TABLE PX_Child NOCHECK CONSTRAINT ALL 

ALTER TABLE PX_Parent NOCHECK CONSTRAINT ALL 

(truncate commands) 

ALTER TABLE PX_Child CHECK CONSTRAINT ALL 

ALTER TABLE PX_Parent CHECK CONSTRAINT ALL 

Ale truncate ciągle mi mówi, że nie może obciąć PX_Parent powodu klucz obcy. Rozglądałem się po sieci i nie mogę znaleźć tego, co robię źle, przepraszam za podstawową naturę tego pytania.

+1

wygląda Kalen Delaney był przypadkowo odpowiedzialny za uruchomienie tego pomysłu off. [Tutaj ona wyjaśnia] (http://www.eggheadcafe.com/software/aspnet/29927698/cant-truncate-table.aspx) "musisz opuścić wiązanie referencji, aby skrócić tabelę." –

Odpowiedz

31

Nie można obcinać tabeli, jeśli istnieje jakikolwiek klucz obcy odnoszący się do niej, w tym ograniczenia wyłączone. Musisz albo usunąć ograniczenia klucza obcego, albo użyć komendy DELETE.

+1

Zobacz poniżej moją (5 lat) odpowiedź, aby szybko wygenerować "DROP CONSTRAINT" i "ADD CONSTRAINT" SQL – RJB

5

Serwer SQL nie pozwoli ci obciąć tabeli, gdy ograniczenie istnieje, nawet jeśli jest wyłączone. Upuść wiązanie i ponownie utwórz je po obcięciu tabeli. Lub upuść i ponownie utwórz tabele, w zależności od tego, co jest łatwiejsze w aplikacji.

+2

Co masz na myśli, że nie jest to transakcyjne polecenie? Możesz go z powrotem przywrócić. 'CREATE TABLE Blah (a int); INSERT Blah VALUES (1); WYBIERZ * Z BLA; BEGIN TRAN; TRUNCATE TABLE Blah; WYBIERZ * Z BLA; ROLLBACK TRAN SELECT * OD BLA; DROP TABLE Blah'. Obcinaj utwory przez dealokowanie całych stron, a nie usuwanie wierszy, ale nadal transakcje. – ErikE

+0

@Emtucifor: Ups, wydaje mi się, że źle zinterpretowałem dokumentację, masz rację! Usunąłem ten fragment dezinformacji. –

+0

@Emtucifor, @pgroke, w pewnym sensie obie są poprawne, ponieważ standard umożliwia TRUNCATE bycie nietransakcyjnym, ale implementacje umożliwiają jego transakcję. Stąd TRUNCATE, jak zdefiniowano, nie obiecuje, że można wycofać, ale SqlServer (i Postgres) dodaje tę obietnicę poza standard. –

10

Istnieje łatwiejszy sposób. Miałem do czynienia z tym samym problemem i znalazłem to rozwiązanie: https://www.mssqltips.com/sqlservertip/3347/drop-and-recreate-all-foreign-key-constraints-in-sql-server/

Jeśli po prostu uruchomisz zapytanie w DB, wygeneruje T-SQL, który musisz uwzględnić przed/po sproc, aby usunąć i następnie przywróć wszystkie ograniczenia klucza obcego.

Nie martw się, próbując zrozumieć to samo zapytanie.

CREATE TABLE #x -- feel free to use a permanent table 
(
    drop_script NVARCHAR(MAX), 
    create_script NVARCHAR(MAX) 
); 

DECLARE @drop NVARCHAR(MAX) = N'', 
     @create NVARCHAR(MAX) = N''; 

-- drop is easy, just build a simple concatenated list from sys.foreign_keys: 
SELECT @drop += N' 
ALTER TABLE ' + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
    + ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';' 
FROM sys.foreign_keys AS fk 
INNER JOIN sys.tables AS ct 
    ON fk.parent_object_id = ct.[object_id] 
INNER JOIN sys.schemas AS cs 
    ON ct.[schema_id] = cs.[schema_id]; 

INSERT #x(drop_script) SELECT @drop; 

-- create is a little more complex. We need to generate the list of 
-- columns on both sides of the constraint, even though in most cases 
-- there is only one column. 
SELECT @create += N' 
ALTER TABLE ' 
    + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
    + ' ADD CONSTRAINT ' + QUOTENAME(fk.name) 
    + ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name) 
    -- get all the columns in the constraint table 
    FROM sys.columns AS c 
    INNER JOIN sys.foreign_key_columns AS fkc 
    ON fkc.parent_column_id = c.column_id 
    AND fkc.parent_object_id = c.[object_id] 
    WHERE fkc.constraint_object_id = fk.[object_id] 
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') 
    + ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rt.name) 
    + '(' + STUFF((SELECT ',' + QUOTENAME(c.name) 
    -- get all the referenced columns 
    FROM sys.columns AS c 
    INNER JOIN sys.foreign_key_columns AS fkc 
    ON fkc.referenced_column_id = c.column_id 
    AND fkc.referenced_object_id = c.[object_id] 
    WHERE fkc.constraint_object_id = fk.[object_id] 
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') + ');' 
FROM sys.foreign_keys AS fk 
INNER JOIN sys.tables AS rt -- referenced table 
    ON fk.referenced_object_id = rt.[object_id] 
INNER JOIN sys.schemas AS rs 
    ON rt.[schema_id] = rs.[schema_id] 
INNER JOIN sys.tables AS ct -- constraint table 
    ON fk.parent_object_id = ct.[object_id] 
INNER JOIN sys.schemas AS cs 
    ON ct.[schema_id] = cs.[schema_id] 
WHERE rt.is_ms_shipped = 0 AND ct.is_ms_shipped = 0; 

UPDATE #x SET create_script = @create; 

PRINT @drop; 
PRINT @create; 

/* 
EXEC sp_executesql @drop 
-- clear out data etc. here 
EXEC sp_executesql @create; 
*/ 

Generuje wiązkę:

ALTER TABLE [dbo].[Whatever] DROP CONSTRAINT.... 
-- 
ALTER TABLE [dbo].[Whatever] ADD CONSTRAINT.... 
+6

zła rada: "Nie martw się, próbując zrozumieć to samo zapytanie". Nigdy nie uruchamiaj niczego, co wyskoczyło z sieci bez zrozumienia go. –

+0

To prawda, ale nie była to wersja produkcyjna DB – RJB

+2

Istnieje różnica między zrozumieniem działania zapytania a upewnieniem się, że nie wyrządzi on żadnej szkody. To ostatnie jest prawie zawsze łatwiejsze. – wolfrevokcats

Powiązane problemy