【发布时间】: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