2016-02-02 76 views
-2

在存储过程中,我想更改我的代码,以便在其他数据库上使用它。 数据:是数据库的名称 我有其他数据库,例如:DATA2和DATA3。我需要用参数@LocalBase替换DATA。SQL Server:具有多个参数的存储过程

IF NOT EXISTS (SELECT * FROM ['' + @localBase + ''].SYS.SCHEMAS WHERE NAME = @DestinationSchema)   
    BEGIN 
     SELECT @SQL = N'USE DATA; EXEC(''CREATE SCHEMA '' + @DestinationSchema + '')' 
     EXEC sp_executesql @SQL 
     INSERT INTO dbo.TableLog SELECT @id, @SourceServer, @SourceSchema, 'GetAllTables', @DestinationSchema, CURRENT_TIMESTAMP, 'Schema ' + @DestinationSchema + ' created', 2 
    END 

是否有可能(正确)做到这一点? `

@SQL=N'IF NOT EXISTS (SELECT * FROM ['' + @localBase + ''].SYS.SCHEMAS WHERE NAME = @DestinationSchema)' 
EXEC sp_executesql @SQL 

    BEGIN 
     SELECT @SQL = N'USE ['' + @localBase + '']; EXEC(''CREATE SCHEMA '' + @DestinationSchema + '''')' 
     EXEC sp_executesql @SQL 
      INSERT INTO dbo.TableLog SELECT @id, @SourceServer, @SourceSchema, 'GetAllTables', @DestinationSchema, CURRENT_TIMESTAMP, 'Schema ' + @DestinationSchema + ' created', 2 
    END 

`

我想调用存储过程那样:

DECLARE @RC int 
DECLARE @SourceServer nvarchar(255) 
DECLARE @localBase nvarchar(255) 

SET @SourceServer = 'Serv1,10001' 
SET @localBase = 'DATA1' 

EXECUTE @RC = [dbo].[stor_proc_name] 
    @SourceServer, 
    @localBase 
+1

为什么你要像这样动态创建模式?这有很多红旗,这里有一些非常严重的设计问题。而当你开始使用动态sql时,你需要小心,你不会从我们的老朋友桌面上进行访问。 http://bobby-tables.com/ –

+0

此代码是存储过程代码的一部分。将数据库服务器的表复制到另一台服务器。 存储过程为DATA数据库运行。但我想使它通用于将其应用于其他数据库 – Slim025

+0

嗯,这是有点可怕,但看看你有你的变量@LocalBase。由于这是现在的动态sql字符串的一部分,你将需要'''不'。按照编码,你的字符串中有一个字符串文字。在执行它之前,您需要养成检查动态sql的习惯。如果你看看字符串,你会很快注意到语法错误。 –

回答

0

肖恩是正确的关于这些类型构造的风险。您当前的解决方案容易受到SQL注入的影响,如果您继续使用此路径,则需要非常小心,因为您嵌套了动态SQL结构。 CREATE SCHEMA是在动态SQL中动态构建的,这意味着您不得不为模式名称转义一次,而是两次,一次为CREATE SCHEMA构造(它充当对象名称)和一次为顶级构件级别的动态SQL构造(字符串),否则你有两个级别的可能的SQL注入。

根据您的发言将有望证明了我的意思下面的例子:

DECLARE @SQL nvarchar(max) 
DECLARE @localBase sysname 
DECLARE @DestinationSchema sysname 
SET @localBase = 'a''b]c'; 
SET @DestinationSchema = 'a''b]c'; 
SELECT @SQL = N'USE ' + quotename(@localBase) + '; 
    EXEC(''CREATE SCHEMA ' + replace(quotename(@DestinationSchema), '''', '''''') + ''')' 
print @SQL 
EXEC sp_executesql @SQL 

注意的是,虽然“使用”的语句可以使用QUOTENAME,为CREATE SCHEMA构建正确转义我有逃跑两次;首先,我使用quotename转义字符(因为CREATE SCHEMA构造的名称是一个对象标识符),但我也需要转义(')字符,因为它也被用作字符串(用于EXEC语句)。 一个可能的建议是为了创建不同的模块来构建将用作嵌套动态SQL的字符串。例如(使用相同的例子如上:

CREATE FUNCTION [a].[f_construct_create_schema_statement](@schema_name sysname) 
RETURNS nvarchar(max) 
AS 
BEGIN 
    DECLARE @retval nvarchar(max); 
    SELECT @retval = 'CREATE SCHEMA ' + quotename(@schema_name) + ';' 
    return @retval; 
END 

与前面的脚本更改为以下(这使得它更易于阅读,并更容易找到错误):

DECLARE @SQL nvarchar(max) 
DECLARE @parameters nvarchar(100) 
DECLARE @localBase sysname 
DECLARE @DestinationSchema sysname 
SET @localBase = 'a''b]c'; 
SET @DestinationSchema = 'a''b]c'; 
SELECT @SQL = N'USE ' + quotename(@localBase) + '; 
    DECLARE @SQL nvarchar(max); 
    SELECT @SQL = [a].[f_construct_create_schema_statement](@DestinationSchema); 
    EXEC(@SQL)' 
print @SQL 
set @parameters = '@DestinationSchema sysname' 
EXEC sp_executesql @SQL, @parameters, @DestinationSchema = @DestinationSchema 

使用这种潜水在使用动态SQL时,您仍然必须非常小心,尽可能地避免它,并在允许的情况下使用参数化,但至少您不必直接处理复杂的嵌套转义序列

我希望这个informati在帮助。

-Raul Garcia

+0

非常感谢,我会尝试这种方法,并会告诉你它是否有效。 苗条 – Slim025

相关问题