在SQLite中,确保Tcl变量被视为正确类型的正确方法是什么?
这个活动会话似乎是将number
设置为50
的最简单的场景,但SQLite似乎将:number
视为字符串,将:number+0
和$number
视为数字。
如果改用incr nbr 50
,则SQLite会将:nbr
视为数字。
是否有一种方法可以在Tcl中“声明”变量,以便SQLite根据需要处理它;或者是否应该在SQL表达式中转换每个值?
我想知道如何确保查询总是按照预期的方式工作,而不仅仅是在测试时对“失败”的变量使用cast
;我还没有认识到一些模式或最佳实践。
如果所有变量替换都不被视为字符串并在SQL中转换为一个数字(除非测试发现了问题),那么未来的SQLite版本会不会导致一个“只工作”的示例变成需要转换?
谢谢
% package require sqlite3
3.43.2
% sqlite3 db
% set number 50
50
% db eval {select min(300, :number)}
300
% db eval {select min(300,:number+0)}
50
% db eval "select min(300,$number)"
50
% db eval {select min(300, cast(:number as integer))}
50
% incr nbr 50
50
% db eval {select min(300,:nbr)}
50
% db eval "select min(300,$nbr)"
50
% db eval {create table numbers (id integer, value integer);
insert into numbers values (1,300);}
% db eval {select min(value,:number) from numbers;}
300
字符串
2条答案
按热度按时间wj8zmpe11#
我记得,如果你通过
expr
运行这个值,那么它会得到SQLite的数值解释,但是你需要小心一点,不要在测试时让Tcl把这个值分解为一个文字:字符串
当执行更多面向生产的代码时,这往往不是一个大问题,因为您将常量放在SQL代码中,并且只参数化更改的值(并且这些值很可能具有数值性质)。
如果你真的担心这个问题,可以在SQL中输入
CAST
。在字节码级别,
expr
变成通过一个名为tryCvtToNumeric
的操作发送值,如果值可以有一个数值解释,该操作将为值提供一个数值解释。字面量默认为没有解释。形式上,我们更喜欢C代码不依赖于现有的值解释,而是只要求他们想要的解释,但是tclsqlite扩展(这样命名是为了将其与底层库区分开来)不这样做,而且从来没有这样做过。当处理
BLOB
数据时,这一点更重要。这是当你使用@var
而不是:var
时。9q78igpj2#
据我所知,sqlite会监听它接收到的Tcl值的objtype,并根据它来改变它的行为,我觉得这是对系统的滥用,或者至少是对系统的误解。“type”实际上只是一个缓存值,反映了它上次被当作什么来处理,并没有任何关于该值 * 是什么 * 的意义(就像在数据库类型的意义上)。也就是说,sqlite本身更多地将数据库类型视为指导方针而不是规则,并将很高兴地存储列声明为的内容以外的内容,所以如果您眯起眼睛看得恰到好处,它应该基本上工作正常。
您的示例演示了为什么侦听最后使用的objtype不是一个有效的策略:
字符串
产出:
型
这些年来,我和很多人进行了讨论,他们不能接受Tcl值除了string之外没有其他正式类型的想法,并坚持假装它们有,每个案例都有这个问题。
更进一步,允许Tcl值具有 * 多个 * 缓存对象类型的工作进展缓慢(tip 445隐藏了实现与值关联的objtype的内部细节,因此可以对其进行更改以支持此想法)。(通常称为“Hydra”--一个多头Tcl值系统),因此我有具体的证据证明它可以正常工作并执行。这主要是为了解决一个性能问题,即一个值在快速连续的两次或两次以上的解释中反复使用,被称为“ Flink ”(尽管我已经开始看到人们使用这个术语来表示obtype的更改,即使是一次。我使用“converted”来表示)。在Hydra值模型下,上面的代码将累积它所引用的所有objtype,通过窥探objtype来假装Tcl值具有类型的方法在Hydra世界中完全福尔斯。