我有一个存储过程,其中SELECT语句如下所示:
SELECT @KeyName FROM dbo.FiConfig WITH (NOLOCK) WHERE IssuerKey = @IssuerKey
我在这里创建它:
CREATE PROCEDURE GET_FICONFIG
@IssuerKey INT,
@KeyName NVARCHAR(100)
KeyName
是我要从中检索数据的列名。
我的问题:是否可以传递*
来选择所有列,尽管该过程要求特定的列名称?
编辑: 不幸的是,我觉得我的问题可能很糟糕。我正在寻找一种方法来查看我的存储过程是否可以告诉我是否要从表中选择所有记录,或者只是从记录中选择特定列。我使用一些NULL检查和if / else语句解决了我自己的问题。
答案 0 :(得分:2)
您可以使用动态查询:
CREATE PROCEDURE GET_FICONFIG
@IssuerKey INT,
@KeyName NVARCHAR(100)
AS
declare @s varchar(500) = 'SELECT ' + @KeyName + ' FROM dbo.FiConfig WITH (NOLOCK) WHERE IssuerKey = ' + CAST(@IssuerKey as VARCHAR(10))
exec(@s)
你在这里应该小心。可能Sql Injection
。但是你不能将列名作为参数传递给动态查询,所以没有别的办法。
但您可以从INFORMATION_SCHEMA.COLUMNS
表中进行选择,以确保传递了有效的列名:
IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'FiConfig' AND COLUMN_NAME = @KeyName)
BEGIN
declare @s varchar(500) = 'SELECT ' + @KeyName + ' FROM dbo.FiConfig WITH (NOLOCK) WHERE IssuerKey = ' + CAST(@IssuerKey as VARCHAR(10))
exec(@s)
END
ELSE
THROW...
修改强>
用户@Lamak表示更好地使用QUOTENAME
功能。它会自动在变量值周围添加括号:
CREATE PROCEDURE GET_FICONFIG
@IssuerKey INT,
@KeyName NVARCHAR(100)
AS
declare @s varchar(500) = 'SELECT ' + QUOTENAME(@KeyName) + ' FROM dbo.FiConfig WITH (NOLOCK) WHERE IssuerKey = ' + CAST(@IssuerKey as VARCHAR(10))
exec(@s)
答案 1 :(得分:0)
尝试这样的事情:
DECLARE @SqlCommand nvarchar(max)
SELECT @SqlCommand = 'SELECT ' + @keyname + ' FROM dbo.FiConfig WITH (NOLOCK) WHERE IssuerKey = ' + cast(@IssuerKey as varchar(10))
EXEC sp_executeSQL @SqlCommand
这将允许您传入列名或任意表达式(例如*
或聚合函数,如sum()
)
请记住,这是危险的,因为@keyname上没有验证,所以如果有人传入,它很容易进行SQL注入,例如字符串''; DELETE FROM USERS; --
。
但是,您可以参数化sp_executesql
来缓解此问题;此存储过程的文档位于:
https://msdn.microsoft.com/en-gb/library/ms188001.aspx
sp_executesql
的参数化会阻止您将'*'
作为参数传递给存储过程......