【问题标题】:SQL Server: stored procedure with several parametersSQL Server:具有多个参数的存储过程
【发布时间】:2023-03-31 10:45:01
【问题描述】:

在存储过程中,我想更改我的代码,以便在其他数据库上使用它。 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

【问题讨论】:

  • 为什么要像这样动态创建模式?这有很多危险信号,表明这里存在一些非常严重的设计问题。当您开始使用动态 sql 时,您需要小心不要让我们的老朋友 bobbly 表访问您。 bobby-tables.com
  • 这段代码是存储过程代码的一部分。将数据库服务器的表复制到另一台服务器。存储过程为 DATA 数据库运行。但我想让它通用以将其应用于其他数据库
  • 这有点吓人,但看看你的变量@LocalBase 的位置。由于这现在是动态 sql 字符串的一部分,因此您将需要 ''' 而不是 ''。按照编码,您的字符串中有一个字符串文字。您需要养成在执行动态 sql 之前检查它的习惯。如果您查看字符串,您会很快注意到语法错误。

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


【解决方案1】:

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

请注意,虽然“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 时仍然需要非常小心,尽可能避免它,并在允许的情况下使用参数化,但至少你不必直接处理复杂的嵌套转义序列。

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

-劳尔·加西亚

【讨论】:

  • 非常感谢,我会试试这个方法,如果它有效,我会告诉你。修身
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多