2

重複の可能性:
MSSQL での動的 IN 句の使用

などのパラメーターを含む SQL ステートメントが 1 つあります@StartRow, @StartEnd, @CategoryIds

SELECT * FROM StackOverFlow
WHERE
StartRow = @StartRow
AND StartEnd = @StartEnd
AND CategoryId IN (@CategoryIds)

以下のようにパラメータを設定すると:

DECLARE  @StartRow INT = 1;
DECLARE  @StartRow INT = 10;
DECLARE  @CategoryId NVARCHAR(50);
set @CategoryId ='124,125'

失敗したメッセージは次のとおりです。

nvarchar 値 '124,125' をデータ型 int に変換するときに変換に失敗しました。

以下のような SQL where ステートメントを手動で設定すると:

WHERE
StartRow = @StartRow
AND StartEnd = @StartEnd
AND CategoryId IN (124, 125)

できます。

その変換の問題をどのように解決できますか?

4

2 に答える 2

3

これには動的 SQLを使用する必要があります。だからあなたは書くだろう

DECLARE  @StartRow INT = 1;
DECLARE  @StartRow INT = 10;
DECLARE @CatogoryIds NVARCHAR(50);
SET @CatogoryIds = N'124, 125';
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'
    SELECT * 
    FROM StackOverFlow
    WHERE
        StartRow = ' + @StartRow + 
      N' AND StartEnd = ' + @StartEnd + 
      N' AND CategoryId IN (' + @CategoryIds + N');';
EXEC(@SQL);
GO

これが役立つことを願っています。

于 2012-12-04T15:52:04.253 に答える
2

動的 SQL を使用している場合は、パラメーター化されたクエリと SP_EXECUTESQL を使用する必要があります。

CREATE TABLE T (StartRow INT, StartEnd INT, CategoryID INT);
INSERT T VALUES (1, 10, 124), (1, 10, 125), (1, 10, 126);

DECLARE  @StartRow INT = 1;
DECLARE  @StartEnd INT = 10;
DECLARE  @CategoryId NVARCHAR(50) ='124); DROP TABLE T; --';

DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'SELECT * 
            FROM    T 
            WHERE   StartRow = @Start
            AND     StartEnd = @End
            AND     CategoryID IN (' + @CategoryId + ')'

EXECUTE SP_EXECUTESQL @SQL, N'@Start INT, @End INT', @StartRow, @StartEnd;

動的 SQL の例


これは動的 SQL なしで SQL-Server の XML 拡張機能を使用して行うことができますが、必ずしもそうする必要があるかどうかはわかりませんが、いくつかのテストを実行してパフォーマンスを確認することをお勧めします。

DECLARE  @StartRow INT = 1;
DECLARE  @StartEnd INT = 10;
DECLARE  @CategoryId NVARCHAR(50) ='124,125';


DECLARE @X XML = CAST(N'<root><catid>' + REPLACE(@CategoryID, ',', '</catid><catid>') + '</catid></root>' AS XML);

SELECT  StartRow,
        StartEnd,
        CategoryID
FROM    T
        INNER JOIN
        (   SELECT  [CatID] = cat.value('.', 'int')
            FROM    @X.nodes('/root/catid') c (cat)
        ) c
            ON c.CatID = CategoryID;

XML 拡張を使用した例

クエリは基本的にコンマ区切りの文字列を XML に変換し、その xml を独自のテーブルに分割します。

これにより、不正な形式の文字列が実行されるのではなくエラーがスローされるため、SQL インジェクションのリスクも軽減されます。次の変数を検討してください。

DECLARE  @StartRow INT = 1;
DECLARE  @StartEnd INT = 10;
DECLARE  @CategoryId NVARCHAR(50) ='124,125); DROP TABLE T; --';

XML拡張メソッドで実行すると、これが得られます

Msg 245, Level 16, State 1, Line 13
Conversion failed when converting the nvarchar value '124,125); DROP TABLE T; --' to data type int.

XML 拡張で SQL インジェクションが失敗する

動的 SQL を使用して実行すると、望ましい結果が得られますが、次回実行すると次のようになります。

Msg 208, Level 16, State 1, Line 1
Invalid object name 'T'.

SQL インジェクションの例

上記で使用した XML 方式以外にも文字列を分割する方法がありますが、動的 SQL が唯一の方法ではないことを示すためだけのものであり、入力文字列を制御できない場合は、それを使用しない方が賢明です。悪意のある文字列がデータを破損する可能性があるためです!


答えを完全にするために、テーブル値パラメーターを使用することもできます。例えば

CREATE TYPE dbo.IntegerList AS TABLE (value INT);

CREATE PROCEDURE dbo.ExampleProcedure @StartRow INT, @StartEnd INT, @CategoryID dbo.IntegerList READONLY
AS
BEGIN

    SELECT  *
    FROM    T 
    WHERE   StartRow = @StartRow
    AND     StartEnd = @StartEnd
    AND     CategoryID IN (SELECT Value FROM @CategoryID)
END
于 2012-12-04T16:48:04.000 に答える