2008-09-10 10 views
20

Als Teil meiner Integrationsstrategie habe ich einige SQL-Skripte, die ausgeführt werden, um die Datenbank zu aktualisieren. Das erste, was alle diese Skripte tun, ist zu überprüfen, um zu sehen, ob sie laufen müssen, z.B .:Wie erstelle ich eine gespeicherte Prozedur in SQL Server bedingt?

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 

funktioniert super! Außer wenn ich eine gespeicherte Prozedur hinzufügen muss. Der Befehl "create proc" muss der einzige Befehl in einem Stapel von sql-Befehlen sein. Das Einfügen eines "create proc" in meine IF-Anweisung verursacht diesen Fehler:

 
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch. 

Autsch! Wie lege ich den Befehl CREATE PROC in mein Skript und lasse es nur ausführen, wenn es nötig ist?

Antwort

20

Hier ist, was ich kam mit:

es in einer EXEC Wrap(), etwa so:

if @version <> @expects 
    begin 
     ...snip... 
    end 
else 
    begin 
     exec('CREATE PROC MyProc AS SELECT ''Victory!'''); 
    end 

wirkt wie ein Zauber!

+2

Procs immer wieder neu zu erstellen (bedingt fallend) ist eine viel bessere Lösung.Wenn Sie exec benutzen, gewinnen Sie nichts und es gibt Nachteile; Ihr Proc muss Strings entgehen und alle Zeilennummern in Fehlern beziehen sich auf die Zeilennummer relativ zum Exec-Befehl. – Peter

+0

+1 für die Möglichkeit, andere Bedingungen als Existenz zu behandeln (in meinem Fall @@ Version Laufwerke, ob bestimmte Procs erstellt werden oder nicht) – cmsjr

+1

+1 - Ich habe dies verwendet, um meinen CRUD-Generator zu konfigurieren, um eine Stub-Prozedur zu erstellen, wenn es nicht bereits existieren und dann ändern. Dadurch kann ich meine gespeicherten Prozeduren ändern, die CRUD erstellen, aber alle Berechtigungen beibehalten, die den vorhandenen Prozeduren zugewiesen sind. –

5

Aber achten Sie auf einfache Anführungszeichen innerhalb Ihrer Stored Procedure - sie müssen "entkommen" durch Hinzufügen eines zweiten. Die erste Antwort hat dies getan, aber nur für den Fall, dass Sie es verpasst haben. Eine Falle für junge Spieler.

+0

Diese Antwort sollte ein Kommentar sein. Warum bewegst du es nicht dorthin? – Luiso

3

Versionierung Ihrer Datenbank ist der Weg zu gehen, aber ... Warum geduldig gespeicherte Prozeduren erstellen. Für Views, Stored Procedures, Functions, lassen Sie sie nur bedingt fallen und erstellen Sie sie jedes Mal neu. Wenn du bedingt erstellst, dann wirst du keine Datenbanken bereinigen, die ein Problem oder einen Hack haben, der vor zwei Jahren von einem anderen Entwickler (du oder ich würde das nie gemacht) gemacht hätte, der sicher war, dass er sich erinnern würde, das eine Mal zu entfernen Notfallupdate

1

Ich muss zugeben, ich würde normalerweise mit @Peter einverstanden sein - ich bedingungsbedingt fallen lassen und dann jedes Mal bedingungslos neu erstellen. Ich bin in der Vergangenheit zu oft ertappt worden, als ich versucht habe, die Schemadifferenzen zwischen Datenbanken mit oder ohne Versionskontrolle zu hinterfragen.

Nachdem gesagt, dass Ihr eigener Vorschlag @Josh ist ziemlich cool. Sicherlich interessant. :-)

0

Problem mit dem Löschen und Erstellen ist, dass Sie alle Sicherheitszuschüsse verlieren, die zuvor auf das Objekt angewendet wurden, das gelöscht wird.

+0

Es ist nur ein Problem, wenn Sie diese Grants nicht erneut hinzufügen, nachdem das Verfahren neu erstellt wurde ;-). –

0
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 
0

Verwendung des 'Exists' Befehl in T-SQL, um zu sehen, ob die gespeicherte Prozedur vorhanden ist. Wenn dies der Fall ist, verwenden Sie "Ändern", sonst verwenden Sie "Erstellen"

0

Dies ist ein alter Thread, aber Jobo ist falsch: Create Procedure muss die erste Anweisung in einem Batch sein. Daher können Sie Exists nicht verwenden, um auf Vorhandensein zu testen, und dann Create oder Alter verwenden. Das Mitleid.

+0

True :) (Btw, das sollte wohl eher ein Kommentar sein, als eine Antwort. Aber ich verstehe, dass man noch nicht "kommentieren" kann;) – Leigh

4

SET NOEXEC ON ist guter Weg, einen Teil des Codes auszuschalten

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 

hier gefunden: https://codereview.stackexchange.com/questions/10490/conditional-create-must-be-the-only-statement-in-the-batch

P. S. Ein anderer Weg ist SET PARSEONLY {ON | AUS }.