2015-07-28 62 views
3

在一个简化版本,我试图做这样的事情:sp_executesql的集团通过“必须包含至少一列不是外部引用”

Set @datepart = 'DATEPART(year, myDate)' 
Set @SQLQuery = 'SELECT @datepart AS TIME 
       FROM someTable 
       GROUP BY @datepart' 
Execute sp_executesql @SQLQuery, N'@datepart nvarchar(1000)', @datepart 

,但我得到:

每个GROUP BY表达式都必须包含至少一个不是外部引用的列 。

它工作,如果我不将其参数化,意味着

Set @SQLQuery = 'SELECT ' + @datepart + ' AS TIME 
       FROM someTable 
       GROUP BY ' + @datepart 
Execute sp_executesql @SQLQuery 

回答

2

通过使用参数化查询,你不能达到你正在尝试做的唯一方法是简单的动态查询

Set @SQLQuery = 'SELECT ' + @datepart + ' AS TIME 
       FROM someTable 
       GROUP BY ' + @datepart 
Execute sp_executesql @SQLQuery 

因为变量只是充当动态查询中的值。考虑下面的例子。

DECLARE @datepart NVARCHAR(1000), 
     @SQLQuery NVARCHAR(max) 

SET @datepart = 'DATEPART(year, getdate())' 
SET @SQLQuery = 'SELECT @datepart AS TIME' 

EXECUTE Sp_executesql 
    @SQLQuery, 
    N'@datepart nvarchar(1000)', 
    @datepart 

根据你的回答应该是2015但结果是

DATEPART(year, getdate()) 
0

我想简单的选择应该做这个工作。 查询

SELECT DISTINCT DATEPART(year,mydate) AS TIME 
FROM someTable 

对于动态查询:

Set @SQLQuery = 'SELECT DISTINCT' + @datepart + ' AS TIME 
       FROM someTable' 
Execute sp_executesql @SQLQuery 
+0

这是不可能的参数?我不能在我的用例中使用一个简单的查询,而第二个解决方案 - 就像我刚刚学到的 - 易于使用SQL注入和不良表现一样。 http://stackoverflow.com/questions/31670688/what-is-the-advantage-of-using-parmdefinition-in-sp-executesql – Kiechlus

2

已经完全意识到什么没有人是你已经问了一个问题,自己解决它。 SQL Server已经非常正确地指出,你正试图通过来尝试组,但报告没有输出。

我把你的查询,并提出了版本几乎所有的人都应该能够在SQL 2005+使用:

DECLARE @datepart NVARCHAR(MAX), @SQLQUERY NVARCHAR(MAX) 
SEt @datepart = 'DATEPART(year, myDate)' 
Set @SQLQuery = 'SELECT @datepart AS TIME 
       FROM sys.objects 
       GROUP BY @datepart' 
Execute sp_executesql @SQLQuery, N'@datepart nvarchar(1000)', @datepart 

现在,这将炸毁预期。原因是@datepart是字符串的值。它实际上是试图:

选择字符串“”从“表” GROUP BY“字符串”

在任何时候,它实际上需要的表来回答这个问题。 SQL引发混乱的武器。你需要做什么来实现你似乎什么是试图做的仅仅是在连接字符串在一起,但不可取,这可能是:

DECLARE @datepart NVARCHAR(MAX), @SQLQUERY NVARCHAR(MAX) 
SEt @datepart = 'DATEPART(year, create_date)' 
Set @SQLQuery = 'SELECT ' + @datepart +' AS TIME 
       FROM sys.objects 
       GROUP BY '+ @datepart 
Execute sp_executesql @SQLQuery 

或者在您的具体情况:

DECLARE @datepart NVARCHAR(MAX), @SQLQUERY NVARCHAR(MAX) 
SEt @datepart = 'DATEPART(year, myDate)' 
Set @SQLQuery = 'SELECT ' + @datepart +' AS TIME 
       FROM someTable 
       GROUP BY '+ @datepart 
Execute sp_executesql @SQLQuery 

如果你这样提交代码,我建议尽可能输入简历。这是不好的做法。

0

如果你REPLACE在运行时具有可变的查询,那么你可以达到2015 动态

DECLARE @datepart NVARCHAR(100), 
     @SQLQuery NVARCHAR(max) 

SET @datepart = 'DATEPART(year, getdate())' 
SET @SQLQuery = 'SELECT @datepart AS TIME' 

SET @SQLQuery = REPLACE(@SQLQuery, '@datepart', @datepart) 
exec (@SQLQuery); 
+0

请检查我的回答你的回放,目前是1条评论 – Kiechlus

0

@tinka,这工作正常。但我只是用另一个例子进行了测试,似乎并没有帮助防止SQL注入。也许你的解决方案与使用普通的连接查询相同?

DECLARE @SQLQueryInnen nvarchar(max) 
DECLARE @ParameterDefinition nvarchar(max) 
DECLARE @aufnr nvarchar(200) 
SET @aufnr = '1234; SELECT * FROM sensitiveTable'-- here the attacker inserted an SQL Statement in aufnr 


Set @SQLQueryInnen = 'SELECT * FROM myTable WHERE aufnr = @aufnr' 
Set @SQLQueryInnen = REPLACE(@SQLQueryInnen, '@aufnr', @aufnr) 
Set @ParameterDefinition = '@aufnr nvarchar(200)' 
Execute sp_Executesql @SQLQueryInnen, @ParameterDefinition, @aufnr 
-- Result: The illegal SELECT statement gets executed!!! 

如果我没有更换执行这个例子中,攻击就不会工作,但你:Conversion failed when converting the nvarchar value '1234; SELECT * FROM qdb_tab_imp_me_q_fehler' to data type int.

相关问题