创建数据库脚本中的变量声明

时间:2012-10-09 19:42:17

标签: sql-server variables sqlcmd

我有一个大型数据库创建查询,其开头如下:

USE Master
GO

IF EXISTS(SELECT * FROM sys.sysdatabases where name = 'MyDatabase')
    DROP DATABASE MyDatabase
GO
CREATE DATABASE MyDatabase
GO
USE MyDatabase
GO

我想在开头声明一个变量,如下所示:

DECLARE @MainDB VARCHAR(30) = NULL
USE Master
GO

IF EXISTS(SELECT * FROM sys.sysdatabases where name = @MainDB)
    DROP DATABASE @MainDB
GO
CREATE DATABASE @MainDB
GO
USE @MainDB
GO

我将从命令行执行此查询,并使用sqlcmd工具分配新的数据库名称。但是sql告诉我没有声明变量@MainDB。这是我能做的吗?如果不是,你会如何推荐我解决这个问题?

5 个答案:

答案 0 :(得分:0)

这个问题是一种改变。

How to use a variable for the database name in T-SQL?

简短的回答是你不能拥有可变数据库名称。你必须把你的T-SQL放到一个字符串/ VARCHAR(MAX)中,进行查找和替换,然后执行它。

答案 1 :(得分:0)

很抱歉,但你不能这样做,因为SQL变量只有“batch”-scope,而那些“GO”命令表示批次的边界。因此,每次你通过GO,你的所有变量都会被消灭(它们甚至不再被声明)。

有几种解决方法:

  1. 摆脱GO:这就是我们需要存储过程时所做的事情(不能有任何存储过程) 进入它而不是脚本,但它是一个相当复杂的一系列复杂的技巧,必须相互缠绕,以便将它拉下来。你必须非常熟悉T-SQL才能使用它。

  2. 使用#temp表来保存您的值。这是有效的,因为#temp表具有会话范围而不是批处理范围。

  3. 我相信你也可以使用和操作来自SQLCMD的NTDOS环境变量,虽然我不知道如何做到这一点。

  4. 如果您想要了解其中任何一项,请告诉我哪一个,我可以通过示例更详细地解释。


    糟糕,我错过了“变量数据库名称”部分。这也可以,但你必须添加动态SQL。

答案 2 :(得分:0)

你有多个问题...... GO结束当前批次。所以你的变量不再可见了。你需要移动声明。此外,您不能DROP DATABASE @MainDB,您必须使用动态查询。例如,

GO 
DECLARE @MainDB VARCHAR(30) = 'MyDB';
IF EXISTS(SELECT * FROM sys.sysdatabases where name = @MainDB)
BEGIN
  EXECUTE ('DROP DATABASE '+@MainDB);
END;

答案 3 :(得分:0)

你说你需要从命令行运行它,所以如果你有很多代码依赖于你已经构建的结构,你可以执行以下操作:

  1. 创建脚本的临时副本
  2. 使用您传入的数据库名称作为临时脚本中的参数
  3. 搜索并替换@MainDB
  4. 使用sqlcmd工具
  5. 运行临时脚本

    显然,如果您喜欢此选项,请从脚本中删除DECLARE @MainDB varchar(30)= NULL。

    如果选择这种方法,可以使用各种不同的技术(powershell,python,批处理文件,VBScript ......)实现3个步骤。

    VBScript文件方法:

    set obj = CreateObject("Scriptlet.TypeLib")  
    tempsqlfile = obj.GUID & ".sql" 'get a new name for your sql file
    
    set fso = CreateObject("Scripting.FileSystemObject")
    set objFile = objFSO.OpenTextFile(tempsqlfile, ForReading) 'open the template file
    strSQLText = objFile.ReadAll
    objFile.Close
    
    strNewSQLText = Replace(strSQLText, "@MainDB", Wscript.Arguments(1)) 'replace the db name
    Set objFile = objFSO.OpenTextFile(tempsqlfile, ForWriting)
    objFile.WriteLine strNewText 'write the new file
    objFile.Close
    
    Set Shell = WScript.CreateObject("WScript.Shell")
    commandLine = "osql -E -i " & Wscript.Arguments(0) & -o " & tempsqlfile & ".rpt"
    Set oExec = Shell.Exec(commandLine)
    

    为变量名称道歉 - 我从各个地方剪切并粘贴了点点滴滴,但你应该得到要点。

    (另外 - 为所有这些选项中的VBScript选择道歉,并注意没有错误检查缺少参数)

    如上所述,如果您将该脚本保存为'runmystuff.vbs',那么您可以这样做:

    runmystuff.vbs sqlfile.sql MagicNewDB

    这将在脚本中的所有地方用MagicNewDB替换@MainDB,然后使用osql运行它。

答案 4 :(得分:0)

找到一种方法使cmdline变量等于t-sql变量

USE master
GO
DECLARE @Mydb VARCHAR(30) = "$(mydb)"

IF EXISTS(SELECT * FROM sys.sysdatabases where name = @Mydb)
    print @Mydb
    Execute('create database ' + @Mydb)

我运行的批处理文件如下所示。

sqlcmd -S %1 -i CreateDatabases.sql -v mydb="%2"

我现在可以从sqlcmd运行并输入%1的服务器和%2的所需数据库名称。

感谢大家的回复,他们都帮助我找到了正确的解决方案。