2015-07-28 61 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.

相關問題