2014-05-06 13 views
8

È possibile creare una colonna e inserire valori durante la stessa transazione? Questo fa parte di uno script di aggiornamento. Ho trovato il seguente metodo online, ma non funziona; Viene visualizzato un messaggio di errore: Invalid column name 'IndexNumber'.. Suppongo che ciò sia dovuto al fatto che la transazione non ha ancora creato la colonna, quindi non c'è nulla da inserire.Crea una colonna e inseriscila all'interno della stessa transazione?

Le parti rilevanti del mio script:

Print 'Beginning Upgrade' 
Begin Transaction 
    -- -------------------------------------------------------------------- 
    USE [MyDatabase]; 

    /* Widgets now can be ordered and the order can be modified */ 
    ALTER TABLE [dbo].[Widgets] ADD [IndexNumber] [int] NULL; 

    DECLARE @ind INT 
    SET @ind = 0 
    UPDATE [dbo].[Widgets] 
    SET @ind = [IndexNumber] = @ind + 1; 

    ALTER TABLE [dbo].[Widgets] ALTER COLUMN [IndexNumber] [int] NOT NULL; 
    -- -------------------------------------------------------------------- 
Commit tran 
Print 'Upgrade completed' 

Il motivo per cui [IndexNumber] non è una colonna di identità è che deve essere modificabile.

risposta

14

Un'altra alternativa, se non si desidera dividere il codice in lotti separati, è quello di utilizzare EXEC per creare uno scope/batch nidificati:

Print 'Beginning Upgrade' 
Begin Transaction 
    -- -------------------------------------------------------------------- 
    USE [MyDatabase]; 

    /* Widgets now can be ordered and the order can be modified */ 
    ALTER TABLE [dbo].[Widgets] ADD [IndexNumber] [int] NULL; 

    EXEC('DECLARE @ind INT 
    SET @ind = 0 
    UPDATE [dbo].[Widgets] 
    SET @ind = [IndexNumber] = @ind + 1;'); 

    ALTER TABLE [dbo].[Widgets] ALTER COLUMN [IndexNumber] [int] NOT NULL; 
    -- -------------------------------------------------------------------- 
Commit tran 
Print 'Upgrade completed' 

Il motivo per cui il codice originale non funziona b perché prova a compilare l'intero batch prima di eseguirlo - la compilazione fallisce e quindi non inizia nemmeno la transazione, lascia che altera la tabella.

+0

Sembra buono. L'utilizzo di un exec farà sì che la dichiarazione venga eseguita al di fuori della transazione o dopo di essa? Per quanto riguarda il tuo precedente commento sull'upgrade effettivo non funzionante, potrebbe essere il caso, ma questo è il mio unico vantaggio al momento. – Nenotlep

+0

@Nenotlep - no, sarà ancora all'interno della stessa transazione. –

+0

Questo sembra davvero il modo più semplice per andare, che per me è praticamente il migliore. Usando questo invece di GO non devo riordinare le mie etichette o ripensare il mio flusso di script. Saluti! – Nenotlep

2

Non è possibile aggiungere una nuova colonna e utilizzarla all'interno dello stesso lotto. È necessario inserire GO tra l'aggiunta di una colonna e l'utilizzo.

La transazione è ancora in ordine (è possibile testare modificando Commit tran a rollback tran per vedere che non sono state apportate modifiche).

Print 'Beginning Upgrade' 
Begin Transaction 
    -- -------------------------------------------------------------------- 
    USE [MyDatabase]; 

    /* Widgets now can be ordered and the order can be modified */ 
    ALTER TABLE [dbo].[Widgets] ADD [IndexNumber] [int] NULL; 

    GO 

    DECLARE @ind INT 
    SET @ind = 0 
    UPDATE [dbo].[Widgets] 
    SET @ind = [IndexNumber] = @ind + 1; 

    ALTER TABLE [dbo].[Widgets] ALTER COLUMN [IndexNumber] [int] NOT NULL; 
    -- -------------------------------------------------------------------- 
Commit tran 
Print 'Upgrade completed' 
+0

Questa sembra la soluzione migliore. L'unico problema è che dopo aver iniziato la transazione, eseguo un controllo di versione e, se fallisce, eseguo un 'GOTO Failover;'. L'etichetta di failover viene in realtà dichiarata un po 'dopo' Commit tran', quindi GOTO si trova in un batch diverso rispetto alla dichiarazione -> fail. Qualche suggerimento per quello? – Nenotlep

+0

Puoi spostare quell'etichetta prima di GOTO? – Szymon

+0

Potrebbe essere difficile .. Ecco una copia più grande dello script di aggiornamento: http://pastebin.com/FwKimM66 – Nenotlep

1

chiamata 'go' dopo ALTER TABLE

USE [MyDatabase]; 

/* Widgets now can be ordered and the order can be modified */ 
ALTER TABLE [dbo].[Widgets] ADD [IndexNumber] [int] NULL; 
go 

DECLARE @ind INT 
SET @ind = 0 
UPDATE [dbo].[Widgets] 
SET @ind = [IndexNumber] = @ind + 1; 

ALTER TABLE [dbo].[Widgets] ALTER COLUMN [IndexNumber] [int] NOT NULL; 
-- -------------------------------------------------------------------- 

commit tran