外出先で変数を永続化する方法はありますか?


82

外出先で変数を永続化する方法はありますか?

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')

'USE @bob'行については、このSOの質問を参照してください。


テーブル名をDB名で修飾する必要があるのはなぜですか?この前に同様の質問があったと思います。
shahkalpesh 2009年

そして、そのような変数のデータベース名でテーブル名を修飾する方法はありません。USEステートメントで変数を使用することについての彼の以前の質問で、私は彼が動的SQLですべてを行う必要があり、テーブルにドラッグするすべての苦痛を伴うと思います。
Lasse V. Karlsen

実際のスクリプトは、4つの異なるデータベースを統合します。dbName1、dbName2、dbName3、およびdbName4を見つけて置き換える手順にコメントしました。クライアントが4つの変数を設定するだけで、エラーが発生しにくくなると思いました。
NitroxDM 2009年

質問のタイトルは非常に重要な質問ですが、サンプルコードはひどいものです。受け入れられた答えが示すように、あなたはあなたの例で「行く」必要はありませんでした。その結果、受け入れられた回答はあなたのタイトルの質問に答えません。
グレッグウッズ

回答:


31

このgoコマンドは、コードを個別のバッチに分割するために使用されます。それがまさにあなたがやりたいことであるなら、あなたはそれを使うべきです、しかしそれはバッチが実際に別々であり、それらの間で変数を共有することができないことを意味します。

あなたの場合、解決策は簡単です。goステートメントを削除するだけで、そのコードでは必要ありません。

補足:useステートメントで変数を使用することはできません。変数はデータベースの名前である必要があります。


1
一部のSQLステートメントは、ブロック内の最初のステートメント(GOステートメント間の領域)である必要があります。次に例を示します。CREATEPROCEDUREまたはCREATEFUNCTIONは、スクリプトの先頭またはGOステートメントの直後のいずれかで他のステートメントの前に発生する必要があります(注:これらのステートメントの前に空白とコメントを付けることができます)。このようなステートメントが他のロジックの後に発生する必要があるスクリプトを実行する場合は、GOステートメントが必要です。ただし、ほとんどの場合、GOステートメントは削除できることに同意する必要があります。
ザレフェス2013

@Zarepheth:良い点です。この特定のコードでは必要ありませんが、場合によっては必要になる可能性があることを知っておくと便利です。
guffa 2013

1
なぜ反対票を投じるのですか?あなたが間違っていると思うことが何であるかを説明しなければ、それは答えを改善することはできません。
グッファ2015年

2
@jwize:いいえ、それらを分離する必要はありません。同じブロックで実行できます。
グッファ2015年

1
@Ben:このgoコマンドは、コードを個別のバッチに分割するために使用されます。それがあなたのやりたいことなら、それを使うべきですが、それはバッチが実際には別々であり、それらの間で変数を共有できないことを意味します。
グッファ2015年

127

一時テーブルを使用します。

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

13
素晴らしい答え...あなたは実際に回避策を与えるのではなく、尋ねられた質問に答えました。
Cos Callis 2015

1
これが正解です。素晴らしい解決策。さらに、多数の変数を使用する場合、それらがすべて1つの簡単にアクセスできるテーブルにあり、SPを上下にスクロールして宣言を探す必要がないのも便利です。
ColinMac

15

私はこの質問からのこの答え を好むGOのグローバル変数

これには、元々やりたかったこともできるという追加の利点があります。

注意点は、SQLCMDモードをオンにする([クエリ]-> [SQLCMD]の下)か、すべてのクエリウィンドウでデフォルトでオンにする必要があることです([ツール]-> [オプション]、[クエリ結果]-> [デフォルト]、SQLCMDモードで新しいクエリを開きます)。

次に、次のタイプのコードを使用できます(Oscar E. Fraxedas Tormoによる同じ回答から完全に削除されました)

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

SQLCMDモードでクエリ出力を別のファイル(:out filename)にリダイレクトし、出力をファイルにフラッシュするにはGOを実行する必要があるため、この状況で通常の変数を置き換えるには、この:setvar構文が必要です。物事をバッチに分割することを余儀なくされました。
Anssssss 2015年

すごい!これは実際に本当の正解としてマークされるべきです!
SQL警察

3

SQL Serverを使用している場合は、次のようにスクリプト全体のグローバル変数を設定できます。

:setvar sourceDB "lalalallalal"

後でスクリプトで次のように使用します。

$(sourceDB)

Server Managment StudiでSQLCMDモードがオンになっていることを確認します。これは、トップメニューの[クエリ]をクリックして、SQLCMDモードをオンに切り替えます。

トピックの詳細については、こちらをご覧ください: MSドキュメント


1

これが役立つかどうかわからない

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

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

execute sp_executesql @t

1

一時テーブルはGOステートメントで保持されるため、...

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

きれいではありませんが、機能します


1

一時テーブルに保存/ロードする独自のストアドプロシージャを作成します。

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

次に、これを使用できます。

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

出力:

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

これらも使用できます。

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

の出力exec dbo.MyVariableList

Name    Value
test    42

テーブル内のすべての変数をリストできることは、実際には非常に便利であることがわかりました。したがって、後で変数をロードしなくても、すべてを1か所で確認するためのデバッグ目的に最適です。

これは##プレフィックス付きの一時テーブルを使用するため、GOステートメントを存続させるのに十分です。これは、単一のスクリプト内で使用することを目的としています。

そしてストアドプロシージャ:

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

0

バイナリのyes / noが必要な場合(列が存在する場合など)はSET NOEXEC ON、ステートメントの実行を無効にするために使用できます。 SET NOEXEC ONGO全体(バッチ全体)で機能します。しかし、上のEXEC背を向けることを忘れないSET NOEXEC OFF、スクリプトの終わりに。

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

これはステートメントをコンパイルしますが、それらを実行しません。したがって、存在しないスキーマを参照すると、「コンパイルエラー」が発生します。したがって、スクリプトの2回目の実行(私が行っていること)を「オフ」にすることはできますが、1回目の実行でスクリプトの一部をオフにすることはできません。これは、そうでない列またはテーブルを参照するとコンパイルエラーが発生するためです。まだ存在していません。


0

以下の手順に従って、NOEXECを利用できます。

テーブルを作成する

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

プロシージャのバージョンとバージョンへのポインタを一時テーブルに挿入します #temp_procedure_version

--exampleprocedure_versionポインタ

temp_procedure_version値に挿入(1.0、 '最初のバージョン')

temp_procedure_version値に挿入(2.0、 '最終バージョン')

次に、プロシージャのバージョンを取得します。次のステートメントのようにwhere条件を使用できます。

どこ@ProcedureVersion=ProcedureVersionから選択#temp_procedure_versionする pointer='first version'

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

-ここにプロシージャバージョン1.0を挿入します

プロシージャバージョン1.0を....として作成します。

SET NOEXEC OFF -- execution is ON

ここ@ProcedureVersion=ProcedureVersionから選択#temp_procedure_versionpointer = '最終バージョン'

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

プロシージャバージョン2.0を次のように作成します。

SET NOEXEC OFF -- execution is ON

-一時テーブルを削除します

ドロップテーブル #temp_procedure_version

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.