如何执行以下操作:使用@databasename

jobtbby3  于 2021-08-09  发布在  Java
关注(0)|答案(7)|浏览(349)
DECLARE @DatabaseName NVARCHAR(max); SET @DatabaseName = 'MainDb'
 USE @DatabaseName

不会有用的。怎么做?

yptwkmov

yptwkmov1#

如果要这样动态地执行,就必须使用动态sql。这意味着您要在该数据库的上下文中执行的任何操作,也需要包含在动态sql语句中。
i、 e.假设您要列出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()函数,它将参数 Package 在方括号中:

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

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

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

EXECUTE(@SQL);
vmpqdwk3

vmpqdwk32#

如果在ssms中运行脚本,可以使用sqlcmd模式(在查询菜单下)为数据库名称编写变量脚本。

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

select * from sys.tables
mec1mxoz

mec1mxoz3#

改用同义词

而不是动态sql来做等价的 USE @Database ,我可以提出一些“预处理动态sql”对您来说是更好的解决方案吗?当然,这取决于为什么需要动态use语句。我假设您从一开始就不能使用连接字符串中的正确数据库(这是处理此问题的最佳方法)。
我建议的动态sql是从为要引用的每个对象创建同义词开始:

CREATE SYNONYM dbo.CustomName FOR SomeDatabase.SomeSchema.SomeObject

然后在存储过程中或者在动态use语句之后您想做的任何事情中,只需参考 dbo.CustomName .
为了方便地切换,您可以创建一个小的基础设施。用同义词别名和它们将Map到的对象构建一个表。创建一个存储过程来读取此表并运行动态sql来更新同义词。
当您需要切换时,运行该sp,它将穿透您需要的所有对象并重新链接它们。

警告

如果需要不同的进程通过同义词同时访问不同的数据库,则此策略将不起作用。那样的话,你最好用别的方法。
请记住,您仍然可以通过一些聪明的方法避免动态sql。例如,与其将要运行的sp放在主数据库中并让它动态地对每个子数据库执行操作,不如将sp放在每个子数据库中,然后调用每个sp。

cunj1qz1

cunj1qz14#

如果您需要作为部署过程或某个后端过程的一部分来执行此操作,而不是由用户启动某个操作,那么您可以选择将所有内容都放入这样的动态语句中

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

通过使用sqlcmd实用程序和您最喜欢的脚本程序,您可以走老路。我推荐powershell,但对于这个示例,我将使用经典的dos批处理。
假设您的文件c:\input.sql如下所示

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

您可以在多个数据库上执行input.sql,方法是将以下文件放入批处理文件c:\test.bat(该批处理假定与input.sql位于同一目录中)
c:\测试.bat

set var=maindb

"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE" -d %var% -i"input.sql"

set var=master

"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE" -d %var% -i"input.sql"

然后你可以通过
c:>测试.bat
这种方法的优点是
您可以像平常一样开发input.sql
它也没有execute所具有的varchar限制。。
许多选项与脚本powershell,vbs,ms-dos批处理,shell执行
很多sqlcmd选项(输出文件、超时等)

w8f9ii69

w8f9ii695#

EXEC('USE ' + @DatabaseName + ';SELECT --etc')

只要你相信 @DatabaseName 不包含 ;DROP DATABASE MyDB :)

pokxtpni

pokxtpni6#

我发现synonym和exec dynamic sql的混合是我唯一能做的事情(尤其是作为具有多个数据库的存储过程的一部分)。这是一个简化的版本,它实现了从变量名查询数据库。

CREATE PROCEDURE DM_TCM_TO_COMCARE 
    @FROM_DB varchar(100) = '',
    @TO_DB varchar(100) = ''
AS
BEGIN
    --CHECK INPUT VARIABLES

    DROP SYNONYM dbo.From_TableA 
    SET @SQL_SCRIPT = 'CREATE SYNONYM dbo.From_TableA FOR ['+@FROM_DB+'].[dbo].[TableA]'
    exec (@SQL_SCRIPT)

    DROP SYNONYM dbo.To_TableB
    SET @SQL_SCRIPT = 'CREATE SYNONYM dbo.To_TableB FOR ['+@TO_DB+'].[dbo].[TableB]'
    exec (@SQL_SCRIPT)

    select * from dbo.From_TableA
    select * from dbo.To_TableB

    insert into dbo.To_TableB 
         select * from dbo.From_TableA where 1 = 1
    -- etc
END
GO
fkaflof6

fkaflof67#

您必须使用动态sql来实现这一点。
在您开始探索动态sql之前,我建议您阅读这篇优秀的文章http://www.sommarskog.se/dynamic_sql.html

相关问题