Come posso creare in modo condizionale una procedura memorizzata in SQL Server?
-
09-06-2019 - |
Domanda
Come parte della mia strategia di integrazione, ho alcuni script SQL da eseguire per aggiornare il database.La prima cosa che fanno tutti questi script è verificare se devono essere eseguiti, ad esempio:
if @version <> @expects
begin
declare @error varchar(100);
set @error = 'Invalid version. Your version is ' + convert(varchar, @version) + '. This script expects version ' + convert(varchar, @expects) + '.';
raiserror(@error, 10, 1);
end
else
begin
...sql statements here...
end
Funziona alla grande!Tranne se devo aggiungere una procedura memorizzata.Il comando "create proc" deve essere l'unico comando in un batch di comandi SQL.L'inserimento di un "create proc" nella mia istruzione IF provoca questo errore:
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
Ahia!Come posso inserire il comando CREATE PROC nel mio script e farlo eseguire solo se necessario?
Soluzione
Ecco cosa mi è venuto in mente:
Avvolgilo in un EXEC(), in questo modo:
if @version <> @expects
begin
...snip...
end
else
begin
exec('CREATE PROC MyProc AS SELECT ''Victory!''');
end
Funziona come un fascino!
Altri suggerimenti
SET NOEXEC ON è un buon modo per disattivare alcune parti del codice
IF NOT EXISTS (SELECT * FROM sys.assemblies WHERE name = 'SQL_CLR_Functions')
SET NOEXEC ON
GO
CREATE FUNCTION dbo.CLR_CharList_Split(@list nvarchar(MAX), @delim nchar(1) = N',')
RETURNS TABLE (str nvarchar(4000)) AS EXTERNAL NAME SQL_CLR_Functions.[Granite.SQL.CLR.Functions].CLR_CharList_Split
GO
SET NOEXEC OFF
PSUn altro modo è impostato parseonly {on | SPENTO }.
Ma fai attenzione alle virgolette singole all'interno della Stored Procedure: devono essere "escape" aggiungendone una seconda.La prima risposta ha fatto questo, ma nel caso te lo fossi perso.Una trappola per i giovani giocatori.
Versionare il database è la strada da percorrere, ma...Perché creare procedure memorizzate in modo condizionale.Per visualizzazioni, procedure memorizzate e funzioni, è sufficiente rilasciarle in modo condizionale e ricrearle ogni volta.Se crei in modo condizionale, non pulirai i database che presentano un problema o un hack inserito 2 anni fa da un altro sviluppatore (tu o io non lo faremmo mai) che era sicuro che si sarebbe ricordato di rimuovere l'unica volta aggiornamento di emergenza.
Il problema con l'eliminazione e la creazione è che si perdono eventuali concessioni di sicurezza precedentemente applicate all'oggetto eliminato.
Devo ammettere che normalmente sarei d'accordo con @Peter: lascio cadere condizionalmente e poi ricreano incondizionatamente ogni volta.Sono stato colto di sorpresa troppe volte in passato mentre cercavo di indovinare le differenze di schema tra i database, con o senza alcuna forma di controllo della versione.
Detto questo, il tuo suggerimento @Josh è davvero interessante.Certamente interessante.:-)
Questo è un vecchio thread, ma Jobo non è corretto:Crea procedura deve essere la prima istruzione in un batch.Pertanto non è possibile utilizzare Exists
per testare l'esistenza e quindi utilizzare uno dei due Create
O Alter
.Pietà.
La mia soluzione è verificare se il proc esiste, in tal caso rilasciarlo e quindi creare il proc (stessa risposta di @robsoft ma con un esempio...)
IF EXISTS(SELECT * FROM sysobjects WHERE Name = 'PROC_NAME' AND xtype='P')
BEGIN
DROP PROCEDURE PROC_NAME
END
GO
CREATE PROCEDURE PROC_NAME
@value int
AS
BEGIN
UPDATE SomeTable
SET SomeColumn = 1
WHERE Value = @value
END
GO
utilizzare il comando "Esiste" in T-SQL per verificare se il processo memorizzato esiste.In tal caso, utilizza "Alter", altrimenti utilizza "Crea"
IF NOT EXISTS(SELECT * FROM sys.procedures WHERE name = 'pr_MyStoredProc')
BEGIN
CREATE PROCEDURE pr_MyStoredProc AS .....
SET NOCOUNT ON
END
ALTER PROC pr_MyStoredProc
AS
SELECT * FROM tb_MyTable