我想在SQL Server 2017中创建一个存储过程并让它在其他地方调用(即Python)。它接受三个参数,stkname
-库存名称,stktype
-库存类型,colname
-输出列(仅返回这些列)。 @colname
是varchar
,用于存储所有必需的列名,用,
分隔。
@colname
,则返回所有列(*
)stkname
或stktype
,请不要对其进行过滤到目前为止,这是我的代码:
create procedure demo
(@stkname varchar(max),
@colname varchar(max),
@stktype varchar(max))
as
begin
----These lines are pseudo code -----
select
(if @colname is not null, @colname, else *)
from
Datatable
(if @stkname is not null, where stkname = @stkname)
(if @stktype is not null, where stktype = @stktype)
---- pseudo code end here-----
end
所需的结果是
exec demo @colname= 'ticker,price', @stktype = 'A'
对于stktype ='A'的所有记录返回两列-报价器和价格。
我可以想象有可能使用“动态SQL”,但不能做到“优雅”,我需要编写2 * 2 * 2 = 8种情况。
我该如何更好地实现它?
PS:这个问题不是重复的,因为不仅我需要传递列名,而且还需要“通过其他参数生成查询”
答案 0 :(得分:4)
您需要动态SQL,但是您无需为每个排列编写一个案例,并且防止恶意行为的确不是那么困难。
find
目前尚不清楚tee
和CREATE PROCEDURE dbo.demo -- always use schema prefix
@stkname varchar(max) = NULL,
@colnames nvarchar(max) = NULL, -- always use Unicode and use a proper name
@stktype varchar(max) = NULL
AS
BEGIN
DECLARE @sql nvarchar(max);
SELECT @sql = N'SELECT ' + STRING_AGG(QUOTENAME(LTRIM(RTRIM(x.value))), ',')
FROM STRING_SPLIT(@colnames, ',') AS x
WHERE EXISTS
(
SELECT 1 FROM sys.columns AS c
WHERE LTRIM(RTRIM(x.value)) = c.name
AND c.[object_id] = OBJECT_ID(N'dbo.DataTable')
);
SET @sql += N' FROM dbo.DataTable WHERE 1 = 1'
+ CASE WHEN @stkname IS NOT NULL THEN N' AND stkname = @stkname' ELSE N'' END
+ CASE WHEN @stktype IS NOT NULL THEN N' AND stktype = @stktype' ELSE N'' END;
EXEC sys.sp_executesql @sql,
N'@stkname varchar(max), @stktype varchar(max)',
@stkname, @stktype;
END
列是否真的是stkname
,我对此表示怀疑,您应该将这些声明替换为与列定义匹配的实际数据类型。在任何情况下,使用这种方法,用户都无法将废话传递到列列表中,除非他们以某种方式能够向该表中添加与其废话模式相匹配的列(以及为什么他们仍然键入此内容而不是选择列从已定义的列表中?)。而且,它们作为字符串传递给其他两个参数的任何数据都无法在此处执行。您担心的事情可能是草率代码的结果,您不小心附加了用户输入并未经检查就执行了它,就像这样:
stktype
有关恶意行为的更多信息,请参见: