SQL Server:具有多个参数的存储过程

时间:2016-02-02 16:31:49

标签: sql-server if-statement stored-procedures parameters exists

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

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 个答案:

答案 0 :(得分:0)

Sean对于这些类型构造的风险是正确的。您当前的解决方案容易受到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正确转义“USE”语句,但对于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时仍然要非常小心,尽可能地避免它并在允许时使用参数化,但至少你不必直接处理复杂的嵌套转义序列。

我希望这些信息有所帮助。

-Raul Garcia