日付リテラルは一重引用符で囲む必要があります (読みやすく、エスケープする必要がないため、通常は 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 を使用せずにこれを行うには、いくつかの方法がある可能性があります。ここでは、非常に単純化した回答を示しました。これは、データ型、潜在的な列の数、およびサポートする操作の数によっては実現可能な場合があります。