2016-09-15 5 views
0

テーブルのテキストフィールドにパラメータの値を挿入する必要があるT-SQLストアドプロシージャがあります。パラメータ経由で入力される値は、実際には後で動的SQLとして実行されるクエリです。引用符やダッシュ( - )のような他の特殊文字を使わずに1行だけ入力するとうまくいきます。しかし、引用符や特殊文字を指定するとbarfsとなります。引用符や特殊文字はそれを投げ捨てるからです。文字列をテキストデータ型列に挿入するT-SQL

ストアドプロシージャのための私の入力パラメータは次のとおりです。私はこのようなストアドプロシージャを実行しようとすると

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' 

:来

@input_query text 

私の値は、このです

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

答えは、アポストロフィをエスケープすることです。テキストを変数に割り当てたり、データベースに挿入したりする場合は、アポストロフィをエスケープする必要があります。

エスケープ処理は、プロセッサではなく、クエリパーサーによって処理されます。エスケープアポストロフィで挿入されたデータを参照するか、データベースから取得したデータを見ると、アポストロフィを1つ戻して取得します。あなたのデータには影響しません。

あなたが正しく理解している場合は、後でそのテーブルをクエリしてそれらのクエリを実行できるように、そのクエリをテーブルに挿入しています。いくつかの報告されている報告プログラムの痛みですか?

この概念証明クエリは、これが可能であることを証明します。あなたのスキーマがないので、テーブルの名前を変更する必要がありました。
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の一部としてそれを実行します。 –

関連する問題