如何在USE语句中使用局部变量

Anj*_*nja 5 sql-server t-sql

如何在USE语句中使用局部变量?我得到错误:

消息 911,级别 16,状态 1,第 6 行
数据库“DWSource_@Country”不存在。确保正确输入名称。

代码:

DECLARE @Country varchar(3)
SET @Country='UKR'

USE DWSource_@Country

SELECT  @Country as country,
        count(*) as n_ALL,
        sum(case when LEN(EPOSTA)>0 then 1 else 0 end) as EMAIL1,
        sum(case when LEN(EPOSTA_2)>0 then 1 else 0 end) as EMAIL2

FROM    [dbo].[_data_CRM_S_PARTNER] 
WHERE   VIR = 'SM'
    AND PRAVNA_OSEBA = 0
    AND PROBLEMATICEN = 0   
    AND ISNULL([STATUS],0) IN (0,1) 
    AND ID_DBCLUSTER IN ('112','122','132','212','222','232','312','322','332','311','321','331')
Run Code Online (Sandbox Code Playgroud)

提前致谢!

Br, 安雅

Aar*_*and 8

您不能将变量传递给USE. 您可以在动态 SQL 中执行此操作,也可以构建一个字符串,在每个对象名称前加上数据库前缀。

一种比后一种方法更简洁的动态 SQL 方法,恕我直言,因为它不需要您在动态 SQL 中的每个对象前面注入数据库名称(并且,在这种情况下,还允许您@Country作为参数传递):

DECLARE @country CHAR(3) = 'UKR';
-- assume above is incoming parameter

DECLARE
  @db SYSNAME = N'DWSource_' + @Country,
  @exec NVARCHAR(300), 
  @sql NVARCHAR(MAX);

SET @sql = N'SELECT  @Country as country,
        count(*) as n_ALL,
        sum(case when LEN(EPOSTA)>0 then 1 else 0 end) as EMAIL1,
        sum(case when LEN(EPOSTA_2)>0 then 1 else 0 end) as EMAIL2
FROM    [dbo].[_data_CRM_S_PARTNER] 
WHERE   VIR = ''SM''
    AND PRAVNA_OSEBA = 0
    AND PROBLEMATICEN = 0   
    AND ISNULL([STATUS],0) IN (0,1) 
    AND ID_DBCLUSTER IN (''112'',''122'',''132'',''212'',''222'',
      ''232'',''312'',''322'',''332'',''311'',''321'',''331'')';

SELECT @exec = QUOTENAME(@db) + '.sys.sp_executesql'
EXEC @exec @sql, N'@Country CHAR(3)', @Country;
Run Code Online (Sandbox Code Playgroud)

恕我直言,这两件事至少在某种程度上降低了 SQL 注入的风险。并不是说恶意用户可以用 a 做很多事情,CHAR(3)但是如果您以其他方式使用该模式并使用更大的变量,那么有人可以轻松通过@Country = '1''; DROP TABLE dbo._data_CRM_S_PARTNER; SELECT '''……而在另一个解决方案中,这将是一个问题(同样,如果变量更大)。

EXEC @execErland Sommarskog 关于动态 SQL 的精彩文章中准窃取的方法。

话虽如此,我确实同意 Thomas 的观点,如果您想在多个数据库中运行相同的查询,最好在每个数据库中创建相同的存储过程,然后让应用程序首先连接到所需的数据库地方。由于应用程序必须知道您在哪个国家/地区,因此仅基于此生成连接字符串并在该数据库中调用干净的、无动态 SQL 的存储过程应该不难。


Tho*_*ger 5

你不能。看看BOL 中语句引用/语法USE,这不接受表达式:

USE { database }
Run Code Online (Sandbox Code Playgroud)

看起来好像您正在执行某种形式的数据库分片,并且您希望能够以编程方式处于特定数据库的上下文中。您在这里有两个选择:动态 SQL 或某种形式的数据库和连接字符串细节的应用程序级切换。