有没有一种方法可以持久保留变量?


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问题。


为什么需要用数据库名称来限定表名称?我猜想在此之前有人问过类似的问题。
shahkalpesh,2009年

而且没有办法用这样的变量用数据库名称来限定表名。关于他先前关于在USE语句中使用变量的问题,我猜想他将需要在动态SQL中完成所有工作,而所有麻烦都拖到了表上。
Lasse V. Karlsen

实际的脚本集成了4个不同的数据库。我已评论了查找和替换dbName1,dbName2,dbName3和dbName4的说明。我只是认为,客户端只需设置四个变量就不太容易出错。
NitroxDM

问题标题是一个非常重要的问题,但是示例代码很糟糕。如已接受的答案所示,您的示例中不需要“执行”。结果是接受的答案未回答标题中的问题。
格雷格·伍兹

Answers:


31

go命令用于将代码拆分为单独的批处理。如果这正是您要执行的操作,则应使用它,但这意味着批次实际上是分开的,并且您不能在它们之间共享变量。

在您的情况下,解决方案很简单;您只需删除go语句,该代码中就不需要它们。

注意:您不能在use语句中使用变量,它必须是数据库的名称。


1
某些SQL语句必须是块中第一条语句(GO语句之间的区域)。例如:CREATE PROCEDURE或CREATE FUNCTION都必须在任何其他语句之前发生-在脚本顶部或紧接在GO语句之后(注意:在这些语句之前允许空白和注释)。当运行脚本时,这些语句必须在其他逻辑之后出现,因此需要GO语句。但我必须同意,在大多数情况下,可以删除GO语句。
Zarepheth

@Zarepheth:好点。在此特定代码中不需要它,但是知道在某些情况下可能需要它们很有用。
Guffa 2013年

1
为什么要投票?如果您不解释自己认为是错的是什么,那将无法改善答案。
Guffa 2015年

2
@jwize:不,您不需要将它们分开,可以在同一块中完成。
Guffa'3

1
@Ben:该go命令用于将代码拆分为单独的批处理。如果要这样做,则应该使用它,但这意味着批次实际上是分开的,并且您不能在它们之间共享变量。
Guffa 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
这是正确的答案。不错的解决方案。此外,如果您使用大量变量,它们都位于一个易于访问的表中,而无需在SP中上下滚动以查找您的声明,那将是一个很好的选择。
ColinMac

15

我喜欢这个答案来自这个问题 与GO全局变量

这样做还有一个好处,就是能够同时执行您原本想做的事情。

需要注意的是,您需要打开SQLCMD模式(在Query-> 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文件名),并且要将输出刷新到文件中,您必须执行GO,因此在这种情况下,必须使用:setvar语法替换常规变量,因为被迫将事情分成几批。
Anssssss 2015年

大!实际上,这应该被标记为真正的正确答案!
SQL警察

3

如果您使用的是SQL Server,则可以为整个脚本设置全局变量,例如:

:setvar sourceDB "lalalallalal"

并稍后在脚本中用作:

$(sourceDB)

确保在Server Managment Studi中启用了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

事实证明,能够列出表中的所有变量实际上是非常有用的。因此,即使您以后不加载变量,它也非常适合调试目的,以便将所有内容都集中在一个地方。

这使用带有 ##前缀,因此足以保留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

如果只需要二进制“是/否”(例如是否存在列),则可以使用它SET NOEXEC ON来禁用语句的执行。 SET NOEXEC ON跨GO(跨批次)工作。但记得要打开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

这将编译语句,但不执行它们。因此,如果您引用不存在的架构,您仍然会遇到“编译错误”。因此,它可以“关闭”第二次运行的脚本(我在做什么),但无法在第一次运行时关闭脚本的某些部分,因为如果引用不这样做的列或表,您仍然会遇到编译错误还不存在。


0

您可以按照以下步骤使用NOEXEC:

建立表格

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

将过程版本和指向该版本的指针插入到临时表中 #temp_procedure_version

--example procedure_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_version位置选择指针=“最终版本”

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.