如何在SQL Server动态查询中将列名作为变量传递?
我有下面的查询,它给出了每列的不同值的计数。但我需要在查询中添加where子句条件,例如column1='abc'。我使用这个通用查询,以便通过传递表名,也可以对其他表使用相同的查询如何在SQL Server动态查询中将列名作为变量传递?,sql,sql-server,Sql,Sql Server,我有下面的查询,它给出了每列的不同值的计数。但我需要在查询中添加where子句条件,例如column1='abc'。我使用这个通用查询,以便通过传递表名,也可以对其他表使用相同的查询 DECLARE @query VARCHAR(MAX) SELECT @query = 'SELECT ' + SUBSTRING((SELECT ',' +'COUNT(DISTINCT(' + column_name + ')) AS ' + column_name + ' ' FRO
DECLARE @query VARCHAR(MAX)
SELECT @query =
'SELECT ' + SUBSTRING((SELECT ',' +'COUNT(DISTINCT(' + column_name + ')) AS ' + column_name + ' '
FROM information_schema.columns
WHERE table_name = 'table_name'
FOR XML PAT('')), 2, 100000) + 'FROM table_name'
--PRINT(@query)
EXECUTE(@query)
我试着通过它如下
WHERE
table_name = 'table_name'
AND column1 = 'abc' -- compilation error, obviously
WHERE
table_name = 'table_name'
AND 'column1' = 'abc' -- not working, because it will compare the string values column1 and abc. and both are not equal
然后我尝试了下面的查询,但这也不起作用,当我尝试打印时,它生成了错误的查询
DECLARE @SQL NVARCHAR(MAX), @tname NVARCHAR(100),
@cname NVARCHAR(100), @acc_num NVARCHAR(50), @dp_code NVARCHAR(100)
SET @cname = 'column_name';
SET @acc_num = 'xyz';
SET @tname = 'table_name';
DECLARE @query VARCHAR(MAX);
SET @SQL = ''
;with cols as (
select Table_Schema, Table_Name, Column_Name, Row_Number() over(partition by Table_Schema, Table_Name
order by ORDINAL_POSITION) as RowNum
from INFORMATION_SCHEMA.COLUMNS
)
SELECT @query =
'SELECT ' + SUBSTRING((SELECT ',' +'COUNT(DISTINCT(' + QUOTENAME(column_name, '') + ')) As ' + QUOTENAME(column_name, '')+ ' '
+ ' WHERE ' + 'column_name' + ' = ''' + @acc_num + ''''
FROM cols
WHERE
table_name = @tname
for xml path('')),2,200000) + 'FROM' @tname
--for xml path('');
PRINT @query
--execute (@query)
如果希望在动态查询中使用WHERE子句,则必须将其放在动态查询中FROM子句之后
...
for xml path('')),2,200000) + ' FROM '+ @tname
+ ' WHERE ' + 'column_name' + ' = ''' + @acc_num + ''''
这应该是你想要的。SQL中有一些注释需要注意:
DECLARE @SQL nvarchar(max),
@tname sysname, --note the datatype change
@cname sysname, --note the datatype change
@acc_num nvarchar(50),
@dp_code nvarchar(100); --This is never used in your sample query
SET @cname = 'column_name';
SET @acc_num = 'xyz';
SET @tname = 'table_name';
SET @SQL = N'SELECT ' + NCHAR(13) + NCHAR(10) +
STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) +
N' ' + N'COUNT DISTINCT(' + QUOTENAME(C.Column_Name) + N') AS ' + QUOTENAME(C.Column_Name)
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE C.Table_Name = @tname
ORDER BY C.ORDINAL_POSITION
FOR XML PATH(N'')),1,10,N'') + NCHAR(13) + NCHAR(10) +
N'FROM ' + QUOTENAME(@tname) + NCHAR(13) + NCHAR(10) +
N'WHERE ' + QUOTENAME(@cname) + N' = @Acc_Num;'
PRINT @SQL; --YOur debugging best friend
EXEC sp_executesql @SQL, N'@Acc_Num varchar(100)',@Acc_Num = @acc_num;
这将使用sp_executesql参数化查询,并为您的PRINT语句很好地格式化查询
如果您不明白,请询问。'FROM'@tname将在此处创建语法错误。你也应该把你的陈述参数化其中,“+”列_name“+”=“++@acc_num+`对注入是完全开放的。在sp_executesql中使用参数化语句。此外,删除字符串的第一个字符的常用方法是STUFF{String,1,1,。它比substring更可靠。此查询将仅由内部团队使用。而不是应用程序的一部分。我只需要编写此查询来查看结果内部或外部,这不会给您错误编码实践的原因。注意:当您必须开始使用动态sql传递列和表名时,在e设计。感谢您的回答,如果我需要为所有不同的@Acc_Num获得相同的结果,该怎么办?因此,如果表中@cname列有10个不同的值。它应该返回10行,每个列都有不同的值。就像返回给定的@Acc_Num移动位置一样,更改SELECT并在dynam中添加一个GROUP BYic语句。就像你将使用普通的非动态语句@viveknuna一样。无需传递第二个参数。请帮助你,你需要能够支持代码@viveknuna,而不是我。正如我所说,如果你不理解,请询问你不理解的内容。但请不要要求我为每个sce提供示例nario,这是关于现有答案的。一个小小的支持。我需要在返回的结果中使用cname列的值。我尝试了,但没有做到。OP没有问如何解决注射问题。我只回答了被问到的问题。因此,因为OP没有问如何修复注射,所以你不应该问?如果你的y上有一个洞我们的墙和你被要求修复这个漏洞,你会用一张纸盖住它,假装问题已经解决了吗?你看不到它了,或者正确地填充了它?不解决一个巨大的安全漏洞并不能让这成为一个好的答案。你只是假设存在注射风险。问题没有说明输入是否存在或如何存在e在前端清理,或者甚至有输入。这可能是从数据库获取其变量值的无人值守应用程序的一部分。这是一个非常糟糕的假设。当@acc_num可以作为参数时,没有理由使用='+@acc_num+。这种态度是注入仍然如此普遍的原因,也是人们不这么做的原因不知道如何避免它;因为应该更清楚的人自己并没有遵循好的标准。通过提供一个好的答案来教育人们与提供一个正确的答案同样重要。