sp_executesql 分组依据 "must contain at least one column that is not an outer reference"
sp_executesql Group by "must contain at least one column that is not an outer reference"
在简化版本中,我正在尝试做类似的事情:
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
但我得到:
Each GROUP BY expression must contain at least one column that is not
an outer reference.
如果我不对其进行参数化,它就可以工作,意思是
Set @SQLQuery = 'SELECT ' + @datepart + ' AS TIME
FROM someTable
GROUP BY ' + @datepart
Execute sp_executesql @SQLQuery
我认为简单 select 应该可以完成这项工作。
查询是
SELECT DISTINCT DATEPART(year,mydate) AS TIME
FROM someTable
对于动态查询:
Set @SQLQuery = 'SELECT DISTINCT' + @datepart + ' AS TIME
FROM someTable'
Execute sp_executesql @SQLQuery
通过使用参数化查询,您无法实现您想要做的事情,唯一的方法是简单的动态查询
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())
没有人完全意识到您提出了一个问题并自己解决了。 SQL 服务器非常正确地注意到您正在尝试 按 分组,但报告没有输出。
我接受了你的查询并制作了一个几乎我们所有人都应该能够在 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 是一个 string 值。它实际上是在尝试:
SELECT 'String' 来自 'Table' 分组 'String'
实际上根本不需要 table 来回答这个问题。 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
如果您提交这样的代码,我建议您输入一份简历。这是不好的做法。
如果您 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);
@tinka,这很好用。但我刚刚用另一个例子进行了测试,它似乎对对抗 SQLinjection 没有帮助。也许您的解决方案与使用普通的串联查询相同?
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!!!
如果我在没有 REPLACE 的情况下执行这个例子,攻击将不会起作用,但你会得到:Conversion failed when converting the nvarchar value '1234; SELECT * FROM qdb_tab_imp_me_q_fehler' to data type int.
在简化版本中,我正在尝试做类似的事情:
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
但我得到:
Each GROUP BY expression must contain at least one column that is not an outer reference.
如果我不对其进行参数化,它就可以工作,意思是
Set @SQLQuery = 'SELECT ' + @datepart + ' AS TIME
FROM someTable
GROUP BY ' + @datepart
Execute sp_executesql @SQLQuery
我认为简单 select 应该可以完成这项工作。 查询是
SELECT DISTINCT DATEPART(year,mydate) AS TIME
FROM someTable
对于动态查询:
Set @SQLQuery = 'SELECT DISTINCT' + @datepart + ' AS TIME
FROM someTable'
Execute sp_executesql @SQLQuery
通过使用参数化查询,您无法实现您想要做的事情,唯一的方法是简单的动态查询
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())
没有人完全意识到您提出了一个问题并自己解决了。 SQL 服务器非常正确地注意到您正在尝试 按 分组,但报告没有输出。
我接受了你的查询并制作了一个几乎我们所有人都应该能够在 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 是一个 string 值。它实际上是在尝试:
SELECT 'String' 来自 'Table' 分组 'String'
实际上根本不需要 table 来回答这个问题。 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
如果您提交这样的代码,我建议您输入一份简历。这是不好的做法。
如果您 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);
@tinka,这很好用。但我刚刚用另一个例子进行了测试,它似乎对对抗 SQLinjection 没有帮助。也许您的解决方案与使用普通的串联查询相同?
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!!!
如果我在没有 REPLACE 的情况下执行这个例子,攻击将不会起作用,但你会得到:Conversion failed when converting the nvarchar value '1234; SELECT * FROM qdb_tab_imp_me_q_fehler' to data type int.