-4

次のようなストアド プロシージャがあります。

create stored procedure aaa 
     @columnName nvarchar(10), 
     @comparisonParam nvarchar(10),
     @val nvarchar(100) 
as
    declare @date date
    set @date = convert(@val, date)

    exec('select * from Sheep where ' + @columnName + @comparisonParam  + @date )

実際にクエリが次のようになっている場合:

select * from Sheep where birth_date = 12-12-2000

プロシージャを実行すると、日付値では機能しませんが、string と int では機能します。

4

5 に答える 5

1

日付の値を引用する必要があります。

補足として、私はこれをしないように警告します。動的 SQL を構築する必要がある場合は、SQL インジェクション攻撃、不適切な構文、無効なセマンティクスなどのリスクを考慮する必要があります。

既存のコンポーネントを使用してクエリを作成することを検討してください。いくつかの例:

.NET LINQ (to SQL/Entities) http://msdn.microsoft.com/en-us/library/bb397926.aspx

.NET SqlCommandBuilder http://msdn.microsoft.com/en-us/library /system.data.sqlclient.sqlcommandbuilder.aspx C#/.NET3.5 で動的 SQL クエリを構築する最良の方法を


参照してください。

于 2012-07-14T08:38:14.677 に答える
0

日付リテラルは一重引用符で囲む必要があります (読みやすく、エスケープする必要がないため、通常は CHAR(39) を使用します)。そうでなければ、あなたはこう言っています:

WHERE birth_date = (12) - (12) - (2000)

これは次のように解決されます。

WHERE birth_date = -2000

DATEADD(DAY, -2000, '1900-01-01')または次のように解決されます。

WHERE birth_date = '1894-07-11'

これでは、おそらく希望する結果が得られません。

もちろん、典型的な SQL インジェクションの警告が表示され、それが常に文字列または日付/時刻の列であると仮定して@columnName、ストアド プロシージャを次のように書き直します (可能であれば、動的 SQL を完全に回避しようとするでしょう)。 .

ALTER PROCEDURE dbo.aaa 
  @columnName       NVARCHAR(10), 
  @comparisonParam  NVARCHAR(10),
  @val              NVARCHAR(100)
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @sql NVARCHAR(MAX);

  SET @sql = N'SELECT * FROM dbo.Sheep WHERE '
    + QUOTENAME(@columnName) + @comparisonParam + CHAR(39) 
    + REPLACE(@val, CHAR(39), CHAR(39) + CHAR(39)) 
    + CHAR(39);

  EXEC sp_executesql @sql;
END
GO

潜在的な問題を阻止するために、列とデータ型の検証を追加し、操作が期待どおりであることを確認することができます。例えば

CREATE PROCEDURE dbo.bbb
  @columnName       NVARCHAR(10), 
  @comparisonParam  NVARCHAR(10),
  @val              NVARCHAR(100)
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @delimiter CHAR(1);

  SELECT @delimiter = CASE 
    WHEN [system_type_id] IN 
      (104,48,52,56,127,59,60,62,106,108,122) THEN '' -- numeric
    WHEN [system_type_id] IN 
      (35,40,41,42,43,58,61,99,167,175,231,239) THEN CHAR(39) -- string
    END FROM sys.columns WHERE [object_id] = OBJECT_ID(N'dbo.Sheep')
    AND name = @columnName;

  IF @delimiter IS NULL
  BEGIN
    RAISERROR('Column ''%s'' was not found or an unexpected data type.', 11, 1, 
      @columnName);
    RETURN;
  END

  IF @comparisonParam NOT IN (N'=', N'>=', N'<=', N'<', N'>', N'LIKE')
  BEGIN
    RAISERROR('Comparison param ''%s'' was not valid.', 11, 1, @comparisonParam);
    RETURN;
  END

  DECLARE @sql NVARCHAR(MAX);

  SET @sql = N'SELECT * FROM dbo.Sheep WHERE '
           + QUOTENAME(@columnName) + ' ' + @comparisonParam + ' ' 
           + @delimiter + REPLACE(@val, CHAR(39), CHAR(39) + CHAR(39)) 
           + @delimiter;

  EXEC sp_executesql @sql;
END
GO

ここで、文字列リテラルに明確な日付形式を使用していることを確認してください。12-12-2000良い選択ではありません。20001212はるかに優れています。

動的 SQL を使用せずにこれを行うには、いくつかの方法がある可能性があります。ここでは、非常に単純化した回答を示しました。これは、データ型、潜在的な列の数、およびサポートする操作の数によっては実現可能な場合があります。

于 2012-07-14T15:43:47.147 に答える
0
create stored procedure aaa 
     @columnName nvarchar(10), 
     @comparisonParam nvarchar(10),
     @val nvarchar(100) 
as
    declare @date date
    set @date = convert(@val, date)

    exec('select * from Sheep where ' + @columnName + @comparisonParam  + @date )
于 2013-02-26T06:36:15.573 に答える
0

型指定された日付パラメーターを使用して動的 SQL を作成します。sp_executesqlパラメータ定義とパラメータ値を埋め込み SQL に渡すために使用します。

create procedure aaa 
   @columnName nvarchar(10), 
   @comparisonParam nvarchar(10),
   @val nvarchar(100)
as
    declare @date date, @sql nvarchar(max);
    set @date = convert(@val, date);

    -- Note how @date is a *variable* in the generated SQL:
    set @sql =N'select * from Sheep where ' + 
            quotename(@columnName) + @comparisonParam  + N'@date';

    -- Use sp_executesql and define the type and value of the variable
    exec sp_executesql @sql, N'@date date', @date;
于 2012-07-14T20:08:48.040 に答える
-2

これには、ストアド プロシージャを作成するのではなく、テーブル値関数を作成する必要があります。

次のようなテーブル値関数を使用できます

SELECT * from dbo.CallMyFunction(parameter1, parameter2

例えば。

CREATE FUNCTION Sales.ufn_SalesByStore (@storeid int)
RETURNS TABLE
AS
RETURN 
(
    SELECT P.ProductID, P.Name, SUM(SD.LineTotal) AS 'Total'
    FROM Production.Product AS P 
    JOIN Sales.SalesOrderDetail AS SD ON SD.ProductID = P.ProductID
    JOIN Sales.SalesOrderHeader AS SH ON SH.SalesOrderID = SD.SalesOrderID
    JOIN Sales.Customer AS C ON SH.CustomerID = C.CustomerID
    WHERE C.StoreID = @storeid
    GROUP BY P.ProductID, P.Name
);
GO

参照用にこれを参照してください http://msdn.microsoft.com/en-us/library/ms191165(v=sql.105).aspx

編集

動的SQLを使用する代わりに、考えてみてください

SELECT * FROM 
FROM    [dbo].[Person]
WHERE   ([PersonID] = @PersonID
         OR @AreaID IS NULL
        )
        AND (([Code] BETWEEN @Code AND CHAR(255))
             OR @Code IS NULL
            )
        AND (([Name] BETWEEN @Name AND CHAR(255))
             OR @Name IS NULL
            )
        AND (([Notes] BETWEEN @Notes AND CHAR(255))
             OR @Notes IS NULL
            )
于 2012-07-14T08:37:59.763 に答える