我有以下存储过程,而不是编写完整的存储过程,但其中一些是:
@course int = null,
SET @query = @query + 'Where course_id='+ cast(@course as varchar)
我想知道何时将@course转换为VARCHAR类型,而数据库中的course_id
是INT类型 - 比较是如何进行的?
答案 0 :(得分:6)
SQL Server中两种不同类型之间的比较如下:
首先根据Data Type Precedence的规则比较两种类型的优先级:
具有较低优先级的数据类型将转换为具有较高优先级的数据类型
接下来,优先级较低的类型会转换为优先级较高的类型
为了便于讨论:通过将INT
转换为VARCHAR
来比较VARCHAR
(优先级16,高位)和INT
(优先级27,低位)然后比较两者。
在您的情况下,虽然没有发生转换,因为会发生的事情是@course
值会附加到动态构造的@sql
。不用说,这很糟糕。正确的解决方案是将@course
作为参数传递给dymnamic SQL调用:
@course INT = null
...
SET @query = @query + 'Where course_id= @course';
...
exec sp_executesql @sql, '@course int', @course;
这是:
@sql
答案 1 :(得分:4)
您发布的代码的基本原理是SQL Server需要更改数据类型以允许字符串连接发生。语句本身是一个字符串,提交给优化器,它将比较视为正确的数据类型 - INT到INT。
你可以测试&使用Management Studio / Toad / etc中的以下内容确认自己:
DECLARE @course INT
SET @course = 1234
SELECT 'Where course_id='+ @course
这将失败,读取错误:
将varchar值'Where course_id ='转换为数据类型int。
时转换失败
...同时:
DECLARE @course INT
SET @course = 1234
SELECT 'Where course_id='+ CAST(@course AS VARCHAR) AS output
...将返回:
output
---------------------
Where course_id=1234
答案 2 :(得分:1)
您似乎混淆了比较(a = b
)和作业(SET @a = b
)
在VARCHAR
和INT
之间的比较中,前者始终被强制转换为后者,因此此查询将失败:
SELECT 1
WHERE 'ab' = 1
,因为'ab'
无法投放到INT
。
在作业中,源值(b
)始终强制转换为目标类型(@a
):
DECLARE @av VARCHAR(100)
SET @av = 1
GO
DECLARE @ai INT
SET @ai = 'ab'
GO
由于INT
始终可投放到VARCHAR
,因此第一批将始终成功,而不像将VARCHAR
投放到INT
的第二批。
答案 3 :(得分:1)
在您的查询中,您实际上只是在构建另一个(动态)查询。所以,如果你有例如:
SET @course = 2
SET @query = 'SELECT * FROM Courses'
SET @query = @query + 'Where course_id='+ cast(@course as varchar)
@course的值转换为字符,附加到@query,最后是:
SELECT * FROM Courses Where course_id=2
这是完全有效的sql,无需在执行之前转换任何内容。