我该怎么做:使用@databaseName

问题描述 投票:0回答:8
 DECLARE @DatabaseName NVARCHAR(max); SET @DatabaseName = 'MainDb'
 USE @DatabaseName

行不通。怎么做呢?

sql-server t-sql
8个回答
39
投票

如果你想像那样动态地执行它,你必须使用动态 SQL。意味着您想要在该数据库上下文中执行的任何内容,您也需要包含在动态 SQL 语句中。

即假设您想列出 MainDB 中的所有表:

这不起作用,因为 USE 语句位于不同的上下文中 - 一旦 EXECUTE 运行,以下 SELECT 将不会在同一上下文中运行,因此不会在 MainDb 中运行(除非已设置连接)到MainDb)

DECLARE @DatabaseName NVARCHAR(MAX)
SET @DatabaseName = 'MainDb'
EXECUTE('USE ' + @DatabaseName) -- SQL injection risk!
SELECT name FROM sys.tables

所以你需要这样做:

DECLARE @DatabaseName NVARCHAR(MAX)
SET @DatabaseName = 'MainDb'
EXECUTE('USE ' + @DatabaseName + ';SELECT name FROM sys.tables') -- SQL injection risk!

当然,你需要非常小心 SQL 注入,为此我向你指出 Barry 答案中的链接。

为了防止 SQL 注入,您还可以使用 QUOTENAME() 函数,它将参数括在方括号中:

DECLARE @DatabaseName sysname = 'MainDb'
    , @SQL NVARCHAR(MAX);

SET @SQL = N'USE ' + QUOTENAME(@DatabaseName);

PRINT(@SQL);
-- USE [MainDb]

EXECUTE(@SQL);

18
投票

如果您在 SSMS 中运行脚本,则可以使用 SQLCMD 模式(位于“查询”菜单下)为您的数据库名称编写变量脚本。

:setvar database "MainDb"
use $(database)
go

select * from sys.tables

8
投票

使用同义词代替

我可以提出一些“预处理的动态 SQL”对您来说可能是更好的解决方案吗?当然,这取决于你为什么需要动态USE语句。我假设您确实无法从一开始就使用连接字符串中的正确数据库(这确实是处理此问题的最佳方法)。


我建议的动态 SQL 是首先为要引用的每个对象创建一个同义词:

USE @Database

然后在存储过程或动态 USE 语句之后您想要执行的任何操作中,只需参考 
CREATE SYNONYM dbo.CustomName FOR SomeDatabase.SomeSchema.SomeObject


为了轻松地进行切换,您可以创建一些基础设施。使用同义词别名以及它们将映射到的对象构建一个表。创建一个存储过程来读取此表并运行动态 SQL 来更新您的同义词。

当您需要切换时,运行该 SP,它将删除您需要的所有对象并重新链接它们。

注意事项

如果您需要多个进程通过同义词同时访问不同的数据库,则此策略将不起作用。在这种情况下,您最好采用其他方法。

请记住,您仍然可以通过一些巧妙的方式避免动态 SQL。例如,也许不是将要运行的 SP 放在主数据库中并让它动态地在每个子数据库上执行操作,而是将 SP 放入每个子数据库中,然后调用每个 SP。


3
投票

dbo.CustomName

您可以通过使用 
SQLCMD

实用程序并使用您最喜欢的脚本程序来走老路。我推荐使用 PowerShell,但对于此示例,我将使用经典的 DOS 批处理。 假设您有如下所示的文件 C:\input.sql

EXECUTE('USE ' + @DatabaseName + ';select * from INFORMATION_SCHEMA.TABLES; select * from INFORMATION_SCHEMA.COLUMNS; select * from INFORMATION_SCHEMA.ROUTINES; select * from INFORMATION_SCHEMA.PARAMETERS;')

您可以通过将以下批处理文件放入 C:\Test.bat 来在多个数据库上执行该 input.sql(该批处理假定与 input.sql 位于同一目录中)

C:\测试.bat

select * from INFORMATION_SCHEMA.TABLES; select * from INFORMATION_SCHEMA.COLUMNS; select * from INFORMATION_SCHEMA.ROUTINES; select * from INFORMATION_SCHEMA.PARAMETERS;

然后你可以通过
执行它

C:\>测试.bat

这种方法的优点是

您可以像您一样开发您的Input.SQL 通常会
  • 它也没有 EXECUTE 所具有的 Varchar 限制..
  • 许多选项可用于 PowerShell、VBS、MS DOS Batch、Shell 执行脚本
  • 大量 SQLCMd 选项(输出文件、超时等)

2
投票
只要你相信
EXEC('USE ' + @DatabaseName + ';SELECT --etc')

不会包含

@DatabaseName
:)
    


2
投票

;DROP DATABASE MyDB



1
投票

在开始探索动态 SQL 之前,我建议您阅读这篇优秀的文章

http://www.sommarskog.se/dynamic_sql.html


0
投票

SET @db = 'db_name';

SET @sql = 'USE' + QUOTENAME(@db);

执行 sp_executesql @sql;

© www.soinside.com 2019 - 2024. All rights reserved.