2010-10-02 8 views
22

Ho una tabella denominata PX_Child con una chiave esterna su PX_Parent. Mi piacerebbe disattivare temporaneamente questo vincolo FK in modo che io possa troncare PX_Parent. Non sono sicuro di come questo vada comunque.Disabilitare il vincolo di chiave esterna, non è ancora possibile troncare la tabella? (SQL Server 2005)

ho provato questi comandi

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 

Ma il troncamento mi dice ancora che non può troncare PX_Parent a causa di un vincolo di chiave esterna. Ho guardato intorno alla rete e non riesco a trovare quello che sto facendo male, mi dispiace per la natura di base di questa domanda.

+1

Sembra Kalen Delaney è stato inavvertitamente responsabile di iniziare questa idea off. [Qui chiarisce] (http://www.eggheadcafe.com/software/aspnet/29927698/cant-truncate-table.aspx) "devi eliminare il vincolo di riferimento per troncare la tabella." –

risposta

31

Non è possibile troncare la tabella se è presente una chiave esterna che la fa riferimento, compresi i vincoli disabilitati. È necessario eliminare i vincoli di chiave esterna o utilizzare il comando DELETE.

+1

Vedere la risposta (successiva di 5 anni) sotto per come generare rapidamente il 'DROP CONSTRAINT' e' ADD CONSTRAINT' SQL – RJB

5

Il server SQL non consente di troncare la tabella mentre il vincolo esiste, anche se è disabilitato. Eliminare il vincolo e ricrearlo dopo aver troncato la tabella. Oppure basta rilasciare e ricreare le tabelle, a seconda di cosa è più semplice fare nella propria applicazione.

+2

Cosa intendete per non un comando transazionale? Puoi arrotolarlo bene. 'CREATE TABLE Blah (un int); INSERIRE Blah VALUES (1); SELEZIONA * DA Blah; INIZIA TRAN; TRUNCATE TABLE Blah; SELEZIONA * DA Blah; ROLLBACK TRAN SELECT * DA Blah; DROP TABLE Blah'. Troncare funziona deallocando intere pagine anziché rimuovere righe, ma è ancora transazionale. – ErikE

+0

@Emtucifor: Oops, sembra che abbia interpretato erroneamente la documentazione che hai ragione! Ho rimosso quel pezzo di disinformazione. –

+0

@Emtucifor, @pgroke, in un modo in cui entrambi sono corretti poiché lo standard consente a TRUNCATE di essere non transazionale, ma le implementazioni sono autorizzate a effettuare la transazione. Quindi TRUNCATE come definito non promette un rollback può essere fatto, ma SqlServer (e Postgres) aggiunge quella promessa oltre lo standard. –

10

C'è un modo più semplice. Mi trovai di fronte con lo stesso problema ed ho trovato questa soluzione: https://www.mssqltips.com/sqlservertip/3347/drop-and-recreate-all-foreign-key-constraints-in-sql-server/

Se hai appena esegue questa query nel vostro DB, genererà il T-SQL è necessario includere prima/dopo il tuo sProc, al fine di eliminare e quindi ripristinare eventuali vincoli di chiave esterna.

Non preoccuparti di provare a comprendere questa query.

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; 
*/ 

Genera un mucchio di:

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

cattivo consiglio: "Non preoccuparti di cercare di capire questa query stessa". Non eseguire mai nulla rimosso dalla rete senza comprenderlo –

+0

Vero, ma non era una versione di produzione del DB – RJB

+2

Esiste una differenza tra la comprensione di come funziona una query e l'accertarsi che non faccia alcun danno. Quest'ultimo è quasi sempre più facile. – wolfrevokcats