【问题标题】:TSQL Function returning results of EXECUTE @sqlTSQL 函数返回 EXECUTE @sql 的结果
【发布时间】:2020-12-17 09:26:23
【问题描述】:

我有包含各种设置的设置表,例如:

|SettingOneID | AltSettingOneID | SettingTwoID | AltSettingTwoID | SettingThreeID | AltSettingThreeID | 
|------------ | --------------- | ------------ | --------------- | -------------- | ----------------- | 
|NULL         | NULL            | 1            | NULL            | 2              | 3                 | 

我正在尝试创建一个函数,该函数将使用提供的列名和 bool(bit) 返回设置,以首先检查可选设置或仅使用默认设置, 如果可选设置不可用,它将回退到默认设置

我需要能够动态提供列名。

我使用的是 SQL Server 2016,但需要支持 SQL Server 2012

有效的sql:

    DECLARE @TryOptionalSetting BIT = 1
    DECLARE @DefaultColumnName NVARCHAR(50) = 'SettingOneID';
    DECLARE @OptionalColumnName NVARCHAR(50) = 'AltSettingOneID';
    DECLARE @ID INT;
    DECLARE @settingId INT;
    DECLARE @sql NVARCHAR(4000) = 
            N'DECLARE @ID INT; SELECT @ID =' + @OptionalColumnName + N' FROM [Settings] WHERE [ID] = 1 AND '+CONVERT(NVARCHAR(1), @TryOptionalSetting)+N' = 1;' +
            N'SELECT @ID = COALESCE(@ID,'+@DefaultColumnName+N')  FROM [Settings] WHERE [ID] = '+CONVERT(NVARCHAR(1), @TryOptionalSetting)+N'; SET @out = @ID';
    exec sp_executesql @sql, N'@out INT OUTPUT', @settingId OUTPUT

    SELECT @settingId
    GO

但是,在函数内

CREATE FUNCTION dbo.GetMySetting(
    @DefaultColumnName NVARCHAR(50),
    @OptionalColumnName NVARCHAR(50),
    @TryOptionalSetting BIT
    )
    RETURNS INT
    WITH EXECUTE AS CALLER
    AS
    BEGIN
        DECLARE @settingId INT;
        DECLARE @sql NVARCHAR(4000) = 
                N'DECLARE @ID INT; SELECT @ID =' + @OptionalColumnName + N' FROM [Settings] WHERE [ID] = 1 AND '+CONVERT(NVARCHAR(1), @TryOptionalSetting)+N' = 1;' +
                N'SELECT @ID = COALESCE(@ID,'+@DefaultColumnName+N')  FROM [Settings] WHERE [ID] = '+CONVERT(NVARCHAR(1), @TryOptionalSetting)+N'; SET @out = @ID';
        exec sp_executesql @sql, N'@out INT OUTPUT', @settingId OUTPUT

        RETURN (@settingId);
    END;
GO

它会产生以下错误:

只有函数和一些扩展存储过程可以在函数内执行"

我尝试使用临时表和表值函数,包括删除 sp_executesql,结果如下:

在函数中无效使用副作用运算符“INSERT EXEC”。

【问题讨论】:

  • 您不能在函数中执行此操作。故事结局。函数不能使用EXEC 命令(除了极少数特定的系统过程)。更不用说上面是开放注射了。如果您必须使用动态 SQL,则它需要位于存储过程中并确保 安全。切勿将未经处理的字符串连接到 SQL 查询中。 从不
  • @Larnu ,是的,这是一个很好的观点,尤其是关于 sql 注入的可能性。就我而言,函数/存储过程将不受用户输入的影响。

标签: sql sql-server stored-procedures sql-function


【解决方案1】:

你不能在函数中这样做。如果您想从 SP 获得标量结果,可以使用 SP 的 OUTPUT 参数。

Get scalar value from SELECT statement in stored proc, from within a stored proc

【讨论】:

  • Aaron Bertrand 的链接答案有效,但我会尝试更安全的方法。
【解决方案2】:

SQL 中的存储过程更容易创建,函数结构更严格,支持的子句和功能更少。

最简单的方法是将您的函数转换为存储过程。存储过程没有这个限制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-03
    • 2017-07-18
    相关资源
    最近更新 更多