使用动态 SQL 在数据库之间切换

Sea*_*anR 9 sql-server dynamic-sql sql-server-2008-r2

我有一个涉及在多个数据库之间执行各种命令的过程 - 但是,当我使用动态 SQL 通过“使用 @var”更改数据库时,它实际上并没有更改数据库。

在 [test_db] 中执行:

declare @currentDB varchar(max)
declare @sql varchar(max)

set @currentDB =  DB_NAME()
set @sql = 'use  [' + @currentDB +']'

use master

exec(@sql)

select  DB_NAME()
Run Code Online (Sandbox Code Playgroud)

返回 [Master] 作为当前数据库名称 - 如果我将其use [test_db]作为命令而不是动态放置,则它返回正确的名称。

有没有办法做到这一点,可以在数据库之间正确切换?

Mis*_*goo 16

当然,有办法——总有办法……

如果您声明变量并将数据库和要运行的过程存储在其中,则可以使用参数执行它。

例子

use tempdb;

select db_name();

declare @db sysname = 'master.sys.sp_executesql';

exec @db N'select db_name()';

set @db = 'msdb.sys.sp_executesql';

exec @db N'select db_name()';
Run Code Online (Sandbox Code Playgroud)

然后传递带有参数的查询以在任何数据库中运行是微不足道的

declare @proc sysname, @sql nvarchar(max), @params nvarchar(max);

select 
  @proc = 'ssc.sys.sp_executesql'
, @sql = N'select top 10 name from sys.tables where name like @table order by name;'
, @params = N'@table sysname';

exec @proc @sql, @params, @table = 'Tally%'
Run Code Online (Sandbox Code Playgroud)

我知道这不会改变主查询中的数据库上下文,但想演示如何以安全的参数化方式方便地在另一个数据库中工作,而不会造成太多麻烦。


Sol*_*zky 11

当该子流程结束时,在子流程(即EXEC/ sp_executesql)中进行的会话级更改将消失。这涵盖了USESET语句以及在该子流程中创建的任何本地临时表。全局临时表的创建将在子进程中继续存在,对子进程启动之前存在的本地临时表所做的修改以及对CONTEXT_INFO(我相信)的任何更改也将继续存在。

所以不,您不能动态更改当前数据库。如果您需要执行此类操作,您将需要在该动态 SQL 中执行依赖于新数据库上下文的任何后续语句。