0

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

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 没有声明。这是我能做的吗?如果不是,您将如何建议我解决此问题?

4

5 回答 5

0

抱歉,您不能这样做,因为 SQL 变量只有“批处理”范围,而那些“GO”命令指示您的批处理边界。因此,每次通过 GO 时,所有变量都会被清除(它们甚至不再被声明)。

有几种方法可以解决这个问题:

  1. 摆脱 GO:当我们需要存储过程(其中不能有任何 GO)而不是脚本时,我们会这样做,但它是一系列相当复杂的复杂技巧,必须相互包裹在为了把它拉下来。您必须非常熟练地使用 T-SQL 才能使用它。

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

  3. 我相信您也可以从 SQLCMD 使用和操作 NTDOS 环境变量,尽管我不熟悉具体如何操作。

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


糟糕,我错过了其中的“变量数据库名称”部分。也可以这样做,但是您必须将动态 SQL 添加到组合中。

于 2012-10-09T19:53:55.147 回答
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;
于 2012-10-09T19:54:31.383 回答
0

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

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

显然,如果您喜欢此选项,请从脚本中删除 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 运行它。

于 2012-10-09T22:00:00.003 回答
0

这个问题有点重提。

如何在 T-SQL 中使用变量作为数据库名称?

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

于 2012-10-09T19:47:40.710 回答
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 输入所需的数据库名称。

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

于 2012-10-10T18:34:49.943 回答