2016-09-15 112 views
0

我有一個T-SQL存儲過程,我需要將參數的值插入表中的文本字段。通過參數傳入的值實際上是一個查詢,稍後我將以動態SQL的形式執行。當我只輸入一行而沒有任何引號或其他特殊字符如短劃線( - )時,它可以正常工作。但是,由於引用和特殊字符將它拋棄,所以它帶有一個引號或特殊字符,它是barf。T-SQL將字符串插入文本數據類型列

存儲過程我的輸入參數是:

@input_query text 

我的未來價值是這樣的:

Select 
    t1.*, t2.name 
from 
    nyc..sellers t1 
right join 
    ark..buyers t2 on t1.id = t2.id 
where 
    t1.date = 'period' 
    and t2.period between '2016-01-01' and '2016-12-31' 
    and t2.def = 'u' 

當我嘗試執行這樣的存儲過程:

DECLARE @return_value int 

EXEC @return_value = [dbo].[booksellers] 
    @input_query = N'Select t1.*, t2.name from nyc..sellers t1 right join ark..buyers t2 on 
    t1.id = t2.id where t1.date = 'period' and t2.period between '2016-01-01' and '2016-12-31' and t2.def = 'u'' 

SELECT 'Return Value' = @return_value 

我收到以下錯誤:

INCORRECT SYNTAX NEAR 'period'

我意識到這是因爲引號不會被轉義,即使它們是,下一個錯誤將與未被轉義的日期等等。但我不能混淆輸入查詢 - 它需要按原樣插入。有什麼方法可以讓它起作用嗎?

+0

你知道該怎麼做。去做就對了。你的字符串文字中的單引號需要加倍。沒有別的辦法。 – Jeremy

+0

這是一個糟糕的體系結構的例子,在修復之前會造成問題。如果出於某種原因,您認爲在代碼中生成語句是很好的,只需從代碼中執行即可。不要把它傳遞給proc來執行它...沒有意義。如果它是在代碼中,應用程序開發者會得到錯誤,並且他需要在那裏修正它,因爲該聲明是無效的。此外,它沒有參數化,這只是懶惰,會損害性能並導致注入漏洞。這一切都是錯誤的。 – btberry

+0

可能重複的[在SQL Server中轉義字符](http://stackoverflow.com/questions/5139770/escape-character-in-sql-server) – serverSentinel

回答

0

答案是要逃避你的撇號,如果你要將文本分配給一個變量或插入到數據庫中,它必須完成。

轉義由查詢解析器而不是由處理器處理。當您查看使用轉義撇號插入的數據或從數據庫中檢索數據時,可以使用單引號將其返回。它不會影響你的數據。

如果我正確理解你,你將這個查詢插入到一個表中,以便以後你可以查詢該表並執行這些查詢。排隊報告程序有些疼痛?

這個概念證明查詢證明這是可能的與ESCAPED APOSTROPHES。我沒有你的模式,所以我不得不改變表的名字。
它創建必要的表格和模擬書店過程,將ESCAPED input_query插入到表格中。這是重複3次與3個不同的查詢。然後我使用臨時表和while循環來提取這些查詢並執行它們。

drop table t1; 
create table t1 (
    name varchar(20), 
    id varchar(20), 
    date varchar(20), 
    rid int identity primary key 
) 
drop table t2; 
create table t2 (
    name varchar(20), 
    id varchar(20), 
    [period] datetime, 
    def varchar(10), 
    rid int identity primary key 
) 
drop table QueryData; 
create table QueryData (
    query nvarchar(max), 
    rid int identity primary key 
) 
go 
---- drop procedure dbo.booksellers; 
go 
create procedure dbo.booksellers (
    @input_query nvarchar(max) 
) 
as 
begin 
declare @return int 
insert into QueryData (query) values (@input_query) 

select @return = SCOPE_IDENTITY() 
return @return 
end 
go 

insert into t1 (name, id, date) values 
    ('row1', 'some', 'period'), 
    ('row2', 'more', 'period'), 
    ('row3', 'even', 'not period') 

insert into t2 (name, id, [period], def) values 
    ('period1', 'some', '2016-09-15 06:00', 'u'), 
    ('period2', 'more', '2016-09-15 07:00', 'u'), 
    ('period3', 'less', '2017-09-15 06:00', 'u'), 
    ('period1', 'some', '2017-09-15 06:00', 'u'), 
    ('period2', 'more', '2017-09-15 07:00', 'u'), 
    ('period3', 'less', '2017-09-15 06:00', 'u'), 
    ('period1', 'some', '2017-09-15 06:00', 'x'), 
    ('period2', 'more', '2017-09-15 07:00', 'x'), 
    ('period3', 'less', '2017-09-15 06:00', 'x') 

DECLARE @return_value int 
declare @input_query nvarchar(max) 
set @input_query = N'Select t1.*, t2.name from t1 t1 right join t2 t2 on 
    t1.id = t2.id where t1.date = ''period'' and t2.period between ''2016-01-01'' and ''2016-12-31'' and t2.def = ''u''' 

EXEC @return_value = [dbo].[booksellers] @input_query 
print 'query' 
exec sp_executesql @input_query 
SELECT 'Return Value' = @return_value 

set @input_query = N'Select t1.*, t2.name from t1 t1 right join t2 t2 on 
    t1.id = t2.id where t1.date = ''period'' and t2.period between ''2017-01-01'' and ''2017-12-31'' and t2.def = ''u''' 

EXEC @return_value = [dbo].[booksellers] @input_query 
exec sp_executesql @input_query 
SELECT 'Return Value' = @return_value 

set @input_query = N'Select t1.*, t2.name from t1 t1 right join t2 t2 on 
    t1.id = t2.id where t1.date = ''period'' and t2.period between ''2017-01-01'' and ''2017-12-31'' and t2.def = ''x''' 
EXEC @return_value = [dbo].[booksellers] @input_query 
exec sp_executesql @input_query 
SELECT 'Return Value' = @return_value 


select 'Queued Queries', * from QueryData 
declare @queries table (
    queryId int, 
    rid int identity 
) 

insert into @queries (queryId) 
    select rid from QueryData 

declare @row int 
declare @queryId int 
declare @queryText nvarchar(max) 

select @row = max(rid) from @queries 
while @row > 0 
begin 
    select @queryId = queryId from @queries where rid = @row 
    select @queryText = query from QueryData where rid = @queryId 
    select @queryText 
    exec sp_executesql @input_query 
    delete @queries where rid = @row 
    set @row = @row -1 
end 
+0

我不能改變它 - 我需要能夠保存該查詢字符串的完整性 - 因爲我稍後將其作爲動態sql的一部分執行。 –