sql 即使准备语句中没有记录匹配子句,请求也会因隐式转换而失败
sql request fail with implicit conversion even when no records match clause in prepared statement
我非常喜欢 Whosebug,因为我经常找到解决问题的方法。但今天我迷路了,需要你的帮助。我为我糟糕的英语道歉。
我有一个 spring 批处理软件,可以查询 sql 服务器数据库。为此,我们使用准备好的语句:
select linkcode, cmpcode, doccode, docnum, doclinenum, usrref1 from oas_linkline where linkcode in ( ? , ? ) and usrref1 is not null and usrref1 <> 0
实际上 usrref1 是一个 varchar,因此进行了隐式转换。在我们的例子中,每个匹配子句 < linkcode in (?, ?) > 的记录都应该有一个带有数值的 usrref1,所以这应该不是问题。
但是有一种情况是有问题的。当没有记录匹配 < linkcode in (?, ?) > 时。 DBMS return 出现以下错误:
nested exception is com.microsoft.sqlserver.jdbc.SQLServerException:
Conversion failed when converting the varchar value '00000U20IGRI' to
data type int.
值“00000U20IGRI”涉及来自其他链接代码的记录...
如果我直接将请求与具有任意链接代码值(例如 A 和 B)的 Squirrel 一起使用:
select linkcode, cmpcode, doccode, docnum, doclinenum, usrref1 from oas_linkline where linkcode in ( 'A' , 'B' ) and usrref1 is not null and usrref1 <> 0
没问题,DBMS return 什么都没有,但不会 return 错误。
如果我在我的代码中使用 org.springframework.batch.item.database.JdbcCursorItemReader 中的相同请求,相同,没问题。
如果我用 ?并使用 org.springframework.jdbc.core.PreparedStatementSetter 设置值,BAM!大错误。就像从请求中删除了子句 < linkcode in (?, ?) > 一样。
有人知道这个特定问题的信息吗?感谢您的关注。
在 where
子句或 join
条件中依赖隐式转换时必须小心。如果您使用 implicit
转换,它需要对您表中的所有记录有效,否则您的查询可能会失败,具体取决于所选的执行计划。我遇到过这样的情况,查询已经运行多年,但突然开始失败,因为优化器选择了不同的执行计划。结果它开始扫描不同的记录(即使这些记录不匹配任何 join
或 where
条件)并且隐式转换失败。您可以使用显式转换解决此问题。
来自 MSDN:
test_expression [ NOT ] IN
( subquery | expression [ ,...n ]
)
test_expression: Is any valid expression.
subquery: Is a subquery that
has a result set of one column. This column must have the same data
type as test_expression.
expression[ ,... n ]: Is a list of expressions
to test for a match. All expressions must be of the same type as
test_expression.
链接代码的类型是什么?因为似乎是一个 INT。
'A'和'B'可以转为INT类型,但是'00000U20IGRI'不行
这会导致您出错。
感谢 jaco 和 Luca 的回答。我实际上认为 sql 服务器在使用准备好的语句强制扫描所有行时可能会使用另一个执行计划,从而导致错误。似乎需要在这样的请求中使用数字测试 and ISNUMERIC(usrref1) = 1
.
我非常喜欢 Whosebug,因为我经常找到解决问题的方法。但今天我迷路了,需要你的帮助。我为我糟糕的英语道歉。
我有一个 spring 批处理软件,可以查询 sql 服务器数据库。为此,我们使用准备好的语句:
select linkcode, cmpcode, doccode, docnum, doclinenum, usrref1 from oas_linkline where linkcode in ( ? , ? ) and usrref1 is not null and usrref1 <> 0
实际上 usrref1 是一个 varchar,因此进行了隐式转换。在我们的例子中,每个匹配子句 < linkcode in (?, ?) > 的记录都应该有一个带有数值的 usrref1,所以这应该不是问题。
但是有一种情况是有问题的。当没有记录匹配 < linkcode in (?, ?) > 时。 DBMS return 出现以下错误:
nested exception is com.microsoft.sqlserver.jdbc.SQLServerException: Conversion failed when converting the varchar value '00000U20IGRI' to data type int.
值“00000U20IGRI”涉及来自其他链接代码的记录...
如果我直接将请求与具有任意链接代码值(例如 A 和 B)的 Squirrel 一起使用:
select linkcode, cmpcode, doccode, docnum, doclinenum, usrref1 from oas_linkline where linkcode in ( 'A' , 'B' ) and usrref1 is not null and usrref1 <> 0
没问题,DBMS return 什么都没有,但不会 return 错误。
如果我在我的代码中使用 org.springframework.batch.item.database.JdbcCursorItemReader 中的相同请求,相同,没问题。
如果我用 ?并使用 org.springframework.jdbc.core.PreparedStatementSetter 设置值,BAM!大错误。就像从请求中删除了子句 < linkcode in (?, ?) > 一样。
有人知道这个特定问题的信息吗?感谢您的关注。
在 where
子句或 join
条件中依赖隐式转换时必须小心。如果您使用 implicit
转换,它需要对您表中的所有记录有效,否则您的查询可能会失败,具体取决于所选的执行计划。我遇到过这样的情况,查询已经运行多年,但突然开始失败,因为优化器选择了不同的执行计划。结果它开始扫描不同的记录(即使这些记录不匹配任何 join
或 where
条件)并且隐式转换失败。您可以使用显式转换解决此问题。
来自 MSDN:
test_expression [ NOT ] IN ( subquery | expression [ ,...n ] )
test_expression: Is any valid expression.
subquery: Is a subquery that has a result set of one column. This column must have the same data type as test_expression.
expression[ ,... n ]: Is a list of expressions to test for a match. All expressions must be of the same type as test_expression.
链接代码的类型是什么?因为似乎是一个 INT。
'A'和'B'可以转为INT类型,但是'00000U20IGRI'不行
这会导致您出错。
感谢 jaco 和 Luca 的回答。我实际上认为 sql 服务器在使用准备好的语句强制扫描所有行时可能会使用另一个执行计划,从而导致错误。似乎需要在这样的请求中使用数字测试 and ISNUMERIC(usrref1) = 1
.