在Tcl中,如果用 == 来比较由数字组成的字符串,为什么在SQL中用CAST AS TEXT不能把它还原成字符串?
我错把用 == 来比较两个字符串,应该用 eq。当我试图把一个由数字组成的字符串变量强制转换成文本时,在这样的比较之后,结果是字符串,但再转换成数字时就变成了数字。
有没有办法用SQL来纠正这个问题,还是一旦应用 ==,Tcl就会丢弃原始字符串的值?
之所以很难排查问题,是因为把值写到stdout时,它输出的仍然是原始字符串;如果 puts「知道」字符串的表示形式,那么在SQL中的 cast 也应该知道。
package require sqlite3
sqlite3 db ":memory:"
set id_1 00000
set id_2 00000
puts [db one {select json_object(
'id_1',cast(:id_1 as text),
'id_2',cast(:id_2 as text)
)}]
# {"id_1":"00000","id_2":"00000"}
puts [expr {$id_1 == $id_2}]
# 1
puts "id_1 $id_1 id_2 $id_2"
# id_1 00000 id_2 00000
puts [db one {select json_object(
'id_1',cast(:id_1 as text),
'id_2',cast(:id_2 as text)
)}]
# {"id_1":"0","id_2":"0"} Lost the "00000" <=
set id_3 00000
set id_4 00000
puts [expr {$id_3 eq $id_4}]
# 1
puts "id_3 $id_3 id_4 $id_4"
# id_3 00000 id_4 00000
puts [db one {select json_object(
'id_3',cast(:id_3 as text),
'id_4',cast(:id_4 as text)
)}]
# {"id_3":"00000","id_4":"00000"}
解决方案
Tcl在应用 == 之后会丢弃原始字符串的值吗?
当你对一个变量进行把它当作数字来处理的操作时,该值的内部表示会被强制转换为数字类型,来自它原本的表示形式,作为提高效率的一种手段(这样就不必重复把同一个字符串转成数字)。于是得到的就是整数0,而不是字符串 "00000"。接着sqlite扩展代码会查看这个值,发现它被存储为整数,并使用 sqlite3_bind_int64() 将该值插入到查询中,而不是使用把字符串绑定到查询的函数。像Tcl打印代码这类其他东西仍然会使用原始字符串表示(如果内部的类型强制转换没有造成改变),但sqlite扩展在这里也许有点过于聪明,结果却不尽人意。
所有这一切都发生在SQL语句真正执行之前,这实际上等同于执行了一个 cast(0 as text),从而得到SQL字符串 '0',你所看到的结果就是这样。
Tcl的弱类型系统意味着你必须小心,避免运算符和数值之间的这种不匹配;它不会像某些语言那样帮你自动发现错误。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。