Sql 如何将INT数据库字段与VARCHAR类型进行比较

Sql 如何将INT数据库字段与VARCHAR类型进行比较,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有以下存储过程,不是编写完整的存储过程,但其中一些是: @course int = null, SET @query = @query + 'Where course_id='+ cast(@course as varchar) 我想知道我何时将@course转换为VARCHAR类型,而数据库中我的course\u id是INT类型-比较是如何进行的?您发布的代码的基本原理是,SQL Server需要更改数据类型以允许字符串连接。语句本身是一个字符串,提交给优化器,优化器将比较视为正

我有以下存储过程,不是编写完整的存储过程,但其中一些是:

@course int = null,
    SET @query = @query + 'Where course_id='+ cast(@course as varchar)

我想知道我何时将@course转换为VARCHAR类型,而数据库中我的
course\u id
是INT类型-比较是如何进行的?

您发布的代码的基本原理是,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

还有其他方法。

SQL Server中两种不同类型之间的比较如下:

  • 首先,根据以下规则比较两种类型的优先级:

    优先级较低的数据类型将转换为优先级较高的数据类型

  • 接下来,优先级较低的类型被强制转换为优先级较高的类型

  • 然后在具有较高优先级的类型的原始值和具有较低优先级的类型的转换值之间进行比较

为了便于讨论:
INT
(优先级16,高)和
VARCHAR
(优先级27,低)将通过将
VARCHAR
强制转换为
INT
进行比较,然后对两者进行比较

在您的例子中,虽然没有发生转换,但是发生的是
@course
值被附加到动态构造的
@sql
中。不用说,这很糟糕。正确的解决方案是将
@course
作为参数传递给动态SQL调用:

@course INT = null
...
 SET @query = @query + 'Where course_id= @course';
...
exec sp_executesql @sql, '@course int', @course;
这是:

  • 更快:参数化查询,而不是硬编码值
  • 更安全:如果代码被重构,@counter成为可以进行SQL注入的类型,则可以降低SQL注入的风险
  • 不易出错:不存在传播空值以使整个
    @sql

您似乎混淆了比较(
a=b
)和分配(
SET@a=b

在比较
VARCHAR
INT
时,总是将前者转换为后者,因此此查询将失败:

SELECT  1
WHERE   'ab' = 1
,因为
'ab'
不能强制转换为
INT

在赋值中,源值(
b
)始终转换为目标的类型(
@a
):


由于
INT
始终可强制转换为
VARCHAR
,因此第一批始终会成功,而第二批在查询中将
VARCHAR
强制转换为
INT
,实际上您只是在构建另一个(动态)查询。例如,如果您有:

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,在执行之前不需要转换任何内容。

那么所有输入数据类型都应该只使用varchar类型?我不需要为sql查询的任何输入参数采用任何int或其他数据类型?它是correct@NoviceToDotNet:将所有内容转换为VARCHAR以满足字符串连接要求的复杂性对于DATETIME/等来说是非常痛苦的。我建议对动态SQL使用
sp_executesql
方法,以便在不需要使用显式数据类型的情况下参数化变量转换。如果我使用您sp_executesql告诉我的方法,我不必像我在动态查询中做的那样明确地检查in null属性,比如@course不为null…您上面的查询将自动检查我正在显式执行的@course的is null……比如@course不为null先生,您收到我的问题了吗?我想知道,如果我写入这个长查询没有在动态查询编写中检查isNull…就像我检查course和branch一样,如果@course不为null,那么只为所有参数添加相同的内容。我假设null表示可选筛选器,如果为null,则不应将其添加到WHERE。然后分支
@sql
的构造:
如果@p1不是空集@sql+='和c1=@p1';如果@p2不为空,则设置@sql+='和c2=@p2'等,然后将所有参数传递给动态SQL:
exec sp_executesql@SQL,@p1 int,@p2 int,…,@p1,@p2。动态SQL将使用添加到
@SQL
中的参数,而忽略那些没有添加到
@SQL
中的参数(即null)。这个答案没有抓住问题的关键。没有不同类型的转换,他将查询建立为字符串,但在执行时,like-type将与like-type进行比较
SELECT * FROM Courses Where course_id=2