您的日期文字需要用单引号括起来(我通常使用 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 的情况下,可能有一些方法可以做到这一点——我在这里给出了一个非常简化的答案。这可能是可行的,具体取决于数据类型、潜在列的数量以及您想要支持的操作数量。