Gibt es eine Möglichkeit, eine Variable auf einmal beizubehalten?

82

Gibt es eine Möglichkeit, eine Variable auf einmal beizubehalten?

Declare @bob as varchar(50);
Set @bob = 'SweetDB'; 
GO
USE @bob  --- see note below
GO
INSERT INTO @bob.[dbo].[ProjectVersion] ([DB_Name], [Script]) VALUES (@bob,'1.2')

Siehe diese SO- Frage für die Zeile 'USE @bob'.

NitroxDM
quelle
Warum müssen Sie den Tabellennamen mit dem DB-Namen qualifizieren? Ich denke, eine ähnliche Frage wurde vor dieser gestellt.
Shahkalpesh
Und es gibt keine Möglichkeit, die Tabellennamen mit dem Datenbanknamen in einer solchen Variablen zu qualifizieren. Bei seiner vorherigen Frage zur Verwendung einer Variablen mit der USE-Anweisung muss er vermutlich alles in dynamischem SQL ausführen, mit all den Schmerzen, die sich auf die Tabelle auswirken.
Lasse V. Karlsen
Das eigentliche Skript integriert 4 verschiedene Datenbanken. Ich habe Anweisungen zum Suchen und Ersetzen von dbName1, dbName2, dbName3 und dbName4 kommentiert. Ich dachte nur, es wäre weniger fehleranfällig für den Client, nur vier Variablen festzulegen.
NitroxDM
Der Fragentitel ist eine wirklich wichtige Frage, aber der Beispielcode ist schrecklich. Wie die akzeptierte Antwort zeigt, mussten Sie in Ihrem Beispiel nicht "go". Das Ergebnis ist, dass die akzeptierte Antwort die Frage in Ihrem Titel nicht beantwortet.
Greg Woods

Antworten:

31

Der goBefehl wird verwendet, um Code in separate Stapel aufzuteilen. Wenn Sie genau das tun möchten, sollten Sie es verwenden. Dies bedeutet jedoch, dass die Stapel tatsächlich getrennt sind und Sie keine Variablen zwischen ihnen teilen können.

In Ihrem Fall ist die Lösung einfach; Sie können die goAnweisungen einfach entfernen , sie werden in diesem Code nicht benötigt.

Randnotiz: Sie können keine Variable in einer useAnweisung verwenden, es muss der Name einer Datenbank sein.

Guffa
quelle
1
Einige SQL-Anweisungen müssen die erste Anweisung in einem Block sein (der Bereich zwischen GO-Anweisungen). Beispiel: CREATE PROCEDURE oder CREATE FUNCTION müssen beide vor anderen Anweisungen stehen - entweder am oberen Rand des Skripts oder unmittelbar nach der GO-Anweisung (Hinweis: Leerzeichen und Kommentare sind vor diesen Anweisungen zulässig). Wenn Sie Skripte ausführen, bei denen solche Anweisungen nach einer anderen Logik auftreten müssen, sind die GO-Anweisungen erforderlich. Ich muss jedoch zustimmen, dass in den meisten Fällen die GO-Anweisungen entfernt werden können.
Zarepheth
@ Zarepheth: Guter Punkt. Es wird in diesem speziellen Code nicht benötigt, aber es ist nützlich zu wissen, dass sie in einigen Fällen benötigt werden.
Guffa
1
Warum das Downvote? Wenn Sie nicht erklären, was Sie für falsch halten, kann dies die Antwort nicht verbessern.
Guffa
2
@jwize: Nein, du musst sie nicht trennen, das kann im selben Block gemacht werden.
Guffa
1
@Ben: Der goBefehl wird verwendet, um Code in separate Stapel aufzuteilen. Wenn Sie dies tun möchten, sollten Sie es verwenden. Dies bedeutet jedoch, dass die Stapel tatsächlich getrennt sind und Sie keine Variablen zwischen ihnen teilen können.
Guffa
126

Verwenden Sie eine temporäre Tabelle:

CREATE TABLE #variables
    (
    VarName VARCHAR(20) PRIMARY KEY,
    Value VARCHAR(255)
    )
GO

Insert into #variables Select 'Bob', 'SweetDB'
GO

Select Value From #variables Where VarName = 'Bob'
GO

DROP TABLE #variables
go
RBarryYoung
quelle
13
Tolle Antwort ... Sie haben die gestellte Frage tatsächlich beantwortet, anstatt sich darum zu kümmern.
Cos Callis
1
Das ist die richtige Antwort. Schöne Lösung. Es ist außerdem schön, dass, wenn Sie eine große Anzahl von Variablen verwenden, diese alle in einer leicht zugänglichen Tabelle gespeichert sind und Sie nicht im SP nach Ihren Deklarationen scrollen müssen.
ColinMac
15

Ich bevorzuge diese Antwort aus dieser Frage Globale Variablen mit GO

Dies hat den zusätzlichen Vorteil, dass Sie auch das tun können, was Sie ursprünglich wollten.

Die Einschränkung besteht darin, dass Sie den SQLCMD-Modus (unter Abfrage-> SQLCMD) oder standardmäßig für alle Abfragefenster aktivieren müssen (Extras-> Optionen, dann Abfrageergebnisse-> Standardmäßig neue Abfragen im SQLCMD-Modus öffnen).

Dann können Sie den folgenden Codetyp verwenden (vollständig aus derselben Antwort von Oscar E. Fraxedas Tormo herausgerissen ).

--Declare the variable
:setvar MYDATABASE master
--Use the variable
USE $(MYDATABASE);
SELECT * FROM [dbo].[refresh_indexes]
GO
--Use again after a GO
SELECT * from $(MYDATABASE).[dbo].[refresh_indexes];
GO
Matt Vukomanovic
quelle
Ich habe die Abfrageausgabe im SQLCMD-Modus in eine andere Datei (: out Dateiname) umgeleitet. Um die Ausgabe in die Datei zu übertragen, müssen Sie ein GO ausführen. Daher ist die setvar-Syntax erforderlich, um normale Variablen in dieser Situation zu ersetzen, da Sie ' Sie sind gezwungen, die Dinge in Chargen aufzuteilen.
Anssssss
Toll! Dies sollte eigentlich als die wirklich richtige Antwort markiert werden!
SQL Police
3

Wenn Sie SQL Server verwenden, können Sie globale Variablen für ganze Skripte einrichten, z.

:setvar sourceDB "lalalallalal"

und später im Skript verwenden als:

$(sourceDB)

Stellen Sie sicher, dass der SQLCMD-Modus in Server Managment Studi aktiviert ist. Sie können dies über das Hauptmenü tun. Klicken Sie auf Abfrage und aktivieren Sie den SQLCMD-Modus.

Mehr zum Thema finden Sie hier: MS-Dokumentation

DanteTheSmith
quelle
1

Ich bin mir nicht sicher, ob das hilft

declare @s varchar(50)
set @s='Northwind'

declare @t nvarchar(100)
set @t = 'select * from ' + @s + '.[dbo].[Customers]'

execute sp_executesql @t
shahkalpesh
quelle
1

Temp-Tabellen werden über GO-Anweisungen beibehalten, also ...

SELECT 'value1' as variable1, 'mydatabasename' as DbName INTO #TMP

-- get a variable from the temp table
DECLARE @dbName VARCHAR(10) = (select top 1 #TMP.DbName from #TMP)
EXEC ('USE ' + @dbName)
GO

-- get another variable from the temp table
DECLARE @value1 VARCHAR(10) = (select top 1 #TMP.variable1 from #TMP)

DROP TABLE #TMP

Es ist nicht schön, aber es funktioniert

Remco Nonhebel
quelle
1

Erstellen Sie Ihre eigenen gespeicherten Prozeduren, die in einer temporären Tabelle gespeichert / geladen werden.

MyVariableSave   -- Saves variable to temporary table. 
MyVariableLoad   -- Loads variable from temporary table.

Dann können Sie dies verwenden:

print('Test stored procedures for load/save of variables across GO statements:')

declare @MyVariable int = 42
exec dbo.MyVariableSave @Name = 'test', @Value=@MyVariable
print('  - Set @MyVariable = ' + CAST(@MyVariable AS VARCHAR(100)))

print('  - GO statement resets all variables')
GO -- This resets all variables including @MyVariable

declare @MyVariable int
exec dbo.MyVariableLoad 'test', @MyVariable output
print('  - Get @MyVariable = ' + CAST(@MyVariable AS VARCHAR(100)))

Ausgabe:

Test stored procedures for load/save of variables across GO statements:
  - Set @MyVariable = 42
  - GO statement resets all variables
  - Get @MyVariable = 42

Sie können auch diese verwenden:

exec dbo.MyVariableList       -- Lists all variables in the temporary table.
exec dbo.MyVariableDeleteAll  -- Deletes all variables in the temporary table.

Ausgabe von exec dbo.MyVariableList:

Name    Value
test    42

Es stellt sich heraus, dass es sehr nützlich ist, alle Variablen in einer Tabelle auflisten zu können. Selbst wenn Sie eine Variable später nicht laden, ist es ideal für Debugging-Zwecke, alles an einem Ort zu sehen.

Dies verwendet eine temporäre Tabelle mit einem ##Präfix, sodass es gerade ausreicht, um eine GO-Anweisung zu überleben. Es soll in einem einzigen Skript verwendet werden.

Und die gespeicherten Prozeduren:

-- Stored procedure to save a variable to a temp table.
CREATE OR ALTER PROCEDURE MyVariableSave 
    @Name varchar(255),
    @Value varchar(MAX)
WITH EXECUTE AS CALLER
AS  
BEGIN
    SET NOCOUNT ON
    IF NOT EXISTS (select TOP 1 * from tempdb.sys.objects where name = '##VariableLoadSave')
    BEGIN
        DROP TABLE IF EXISTS ##VariableLoadSave
        CREATE TABLE ##VariableLoadSave
        (
            Name varchar(255),
            Value varchar(MAX)
        )
    END
    UPDATE ##VariableLoadSave SET Value=@Value WHERE Name=@Name
    IF @@ROWCOUNT = 0
        INSERT INTO ##VariableLoadSave SELECT @Name, @Value
END
GO
-- Stored procedure to load a variable from a temp table.
CREATE OR ALTER PROCEDURE MyVariableLoad 
    @Name varchar(255),
    @Value varchar(MAX) OUT
WITH EXECUTE AS CALLER
AS  
BEGIN
    IF EXISTS (select TOP 1 * from tempdb.sys.objects where name = '##VariableLoadSave')
    BEGIN
        IF NOT EXISTS(SELECT TOP 1 * FROM ##VariableLoadSave WHERE Name=@Name)
        BEGIN
            declare @ErrorMessage1 as varchar(200) = 'Error: cannot find saved variable to load: ' + @Name
            raiserror(@ErrorMessage1, 20, -1) with log
        END

        SELECT @Value=CAST(Value AS varchar(MAX)) FROM ##VariableLoadSave
        WHERE Name=@Name
    END
    ELSE
    BEGIN
        declare @ErrorMessage2 as varchar(200) = 'Error: cannot find saved variable to load: ' + @Name
        raiserror(@ErrorMessage2, 20, -1) with log
    END
END
GO
-- Stored procedure to list all saved variables.
CREATE OR ALTER PROCEDURE MyVariableList
WITH EXECUTE AS CALLER
AS  
BEGIN
    IF EXISTS (select TOP 1 * from tempdb.sys.objects where name = '##VariableLoadSave')
    BEGIN
        SELECT * FROM ##VariableLoadSave
        ORDER BY Name
    END
END
GO
-- Stored procedure to delete all saved variables.
CREATE OR ALTER PROCEDURE MyVariableDeleteAll
WITH EXECUTE AS CALLER
AS  
BEGIN
    DROP TABLE IF EXISTS ##VariableLoadSave
    CREATE TABLE ##VariableLoadSave
    (
        Name varchar(255),
        Value varchar(MAX)
    )
END
Contango
quelle
0

Wenn Sie nur ein binäres Ja / Nein benötigen (z. B. wenn eine Spalte vorhanden ist), können Sie SET NOEXEC ONdie Ausführung von Anweisungen deaktivieren. SET NOEXEC ONfunktioniert über GO (über Chargen hinweg). Aber denken Sie daran auf EXEC zurückzudrehen mit SET NOEXEC OFFam Ende des Skripts.

IF COL_LENGTH('StuffTable', 'EnableGA') IS NOT NULL
    SET NOEXEC ON -- script will not do anything when column already exists

ALTER TABLE dbo.StuffTable ADD EnableGA BIT NOT NULL CONSTRAINT DF_StuffTable_EnableGA DEFAULT(0)
ALTER TABLE dbo.StuffTable SET (LOCK_ESCALATION = TABLE)
GO
UPDATE dbo.StuffTable SET EnableGA = 1 WHERE StuffUrl IS NOT NULL
GO
SET NOEXEC OFF

Dadurch werden Anweisungen kompiliert, aber nicht ausgeführt. Sie erhalten also immer noch "Kompilierungsfehler", wenn Sie auf ein nicht vorhandenes Schema verweisen. Es funktioniert also, um das Skript in der zweiten Ausführung "auszuschalten" (was ich tue), aber nicht, um Teile des Skripts in der ersten Ausführung auszuschalten, da beim Verweisen auf Spalten oder Tabellen, die nicht verwendet werden, immer noch Kompilierungsfehler auftreten existiert noch nicht.

Yzorg
quelle
0

Sie können NOEXEC verwenden, indem Sie die folgenden Schritte ausführen:

Tabelle erstellen

#temp_procedure_version(procedure_version varchar(5),pointer varchar(20))

Fügen Sie Prozedurversionen und einen Zeiger auf die Version in eine temporäre Tabelle ein #temp_procedure_version

- Beispiel procedure_version Zeiger

in temp_procedure_versionWerte einfügen (1.0, 'erste Version')

in temp_procedure_versionWerte einfügen (2.0, 'endgültige Version')

Rufen Sie dann die Prozedurversion ab. Sie können die where-Bedingung wie in der folgenden Anweisung verwenden

Wählen Sie @ProcedureVersion=ProcedureVersionaus #temp_procedure_versionwo pointer='first version'

IF (@ProcedureVersion='1.0')
    BEGIN
    SET NOEXEC OFF  --code execution on 
    END
ELSE
    BEGIN 
    SET NOEXEC ON  --code execution off
    END 

- Prozedur Version 1.0 hier einfügen

Erstellen Sie die Prozedur Version 1.0 als .....

SET NOEXEC OFF -- execution is ON

Wählen Sie @ProcedureVersion=ProcedureVersionaus, #temp_procedure_versionwo pointer = 'endgültige Version'

IF (@ProcedureVersion='2.0')
    BEGIN
    SET NOEXEC OFF  --code execution on 
    END
ELSE
    BEGIN 
    SET NOEXEC ON  --code execution off
    END 

Erstellen Sie die Prozedur Version 2.0 als .....

SET NOEXEC OFF -- execution is ON

- Lassen Sie den temporären Tisch fallen

Tabelle ablegen #temp_procedure_version

Viv Pathania
quelle