假设您有以下SQL查询:
SELECT * FROM foo WHERE type = ? AND subtype IN (?)
并且您具有以下可能的数据(我们假设用户界面可以设置这些数据):
var Type int var SubTypes []int
在的情况下SubTypes,我们谈论的是多项选择。
SubTypes
现在,以下代码将不起作用:
rows, err := sqldb.Query(`SELECT * FROM foo WHERE type = ? AND subtype IN (?)`, Type, SubTypes)
因为驱动程序(至少mysql在本示例中使用的驱动程序)无法识别[]slice。键入使其爆炸(SubTypes...)也不起作用,因为A)您不能有多个爆炸参数,而B)即使可以,您的SQL仅支持单个项目((?))。
mysql
[]slice
SubTypes...
(?)
准备的语句不能那样工作,至少在我所知的主要DBMS中不行。我的意思是,在Go中,由database/sql驱动程序实现的对准备好的语句的支持 应该 使用底层DBMS提供的相应功能(如果驱动程序所接口的DB引擎未提供,则驱动程序可能会选择模拟这种支持)。
database/sql
现在,在我熟悉的所有DBMS中,prepared语句的整体思想是,它由DB引擎处理 一次 并缓存;这里的“已处理”是指语法检查,编译为某些特定于数据库的内部表示形式,并确定其执行计划。从术语“已编译”开始,语句的 文本 仅被处理一次,然后每次对预处理语句的调用实际上只是告诉服务器“这是我之前提供给您的预处理语句的ID,这是实际的列表。用于包含的占位符的参数”。这就像编译Go程序,然后使用不同的命令行标志连续多次调用它。
因此,您想出的解决方案是正确的:如果您想在调用之间弄乱语句文本,则一定要使用客户端文本操作1,但不要尝试将其结果用作准备好的语句,除非您真的打算多次执行结果文本。
而且可能会更清楚:您最初尝试准备类似
SELECT a, b FROM foo WHERE a IN (?)
据说您尝试为该IN (?)占位符提供一组值失败了,因为在那里指定多个值所需的逗号 是语法,而不是值的一部分。
IN (?)
我认为准备类似的东西还是可以的
SELECT a, b FROM foo WHERE a IN (?, ?, ?)
因为它不会违反该规则。并不是说这是您的解决方案……
另见本和本 -学习后者将让你与准备语句直接在MySQL客户端播放。
1一些引擎提供服务器端SQL生成,并随后执行生成的文本。