13.5.1 PREPARE 语句

PREPARE stmt_name FROM preparable_stmt

PREPARE语句准备一个 SQL 语句并为其分配一个名称 , stmt_name稍后通过该名称引用该语句。准备好的语句用 执行 EXECUTE和释放 DEALLOCATE PREPARE。有关示例,请参阅第 13.5 节,“准备好的语句”

语句名称不区分大小写。 preparable_stmt是字符串文字或包含 SQL 语句文本的用户变量。文本必须代表单个语句,而不是多个语句。在语句中,? 字符可用作参数标记,以指示稍后执行查询时数据值将绑定到查询的位置。这些 ?字符不应包含在引号中,即使您打算将它们绑定到字符串值。参数标记只能用于数据值应该出现的地方,不能用于 SQL 关键字、标识符等。

如果具有给定名称的准备语句已经存在,则在准备新语句之前隐式释放它。这意味着如果新语句包含错误并且无法准备,则返回错误并且不存在具有给定名称的语句。

准备好的语句的范围是创建它的会话,这有几个含义:

  • 在一个会话中创建的准备好的语句对其他会话不可用。

  • 当会话结束时,无论是正常还是异常,其准备好的语句都不再存在。如果启用了自动重新连接,则不会通知客户端连接丢失。因此,客户端可能希望禁用自动重新连接。请参阅自动重新连接控制

  • 在存储程序中创建的准备好的语句在程序完成执行后继续存在,并且稍后可以在程序外部执行。

  • 在存储程序上下文中准备的语句不能引用存储过程或函数参数或局部变量,因为它们在程序结束时超出范围,并且如果语句稍后在程序外执行则不可用。作为一种解决方法,请改为引用用户定义的变量,这些变量也具有会话范围;参见 第 9.4 节,“用户定义的变量”

从 MySQL 8.0.22 开始,准备语句中使用的参数在语句首次准备时确定其类型,并 EXECUTE在为此准备语句调用时保留此类型(除非重新准备语句,如本节后面所述) . 此处列出了确定参数类型的规则:

  • 作为二元算术运算符的操作数的参数与其他操作数具有相同的数据类型。

  • 如果二元算术运算符的两个操作数都是参数,则参数的类型由运算符的上下文决定。

  • 如果参数是一元算术运算符的操作数,则参数的类型由运算符的上下文决定。

  • 如果算术运算符没有类型确定上下文,则所涉及的任何参数的派生类型都是 DOUBLE PRECISION. 例如,当参数是列表中的顶级节点SELECT时,或者当它是比较运算符的一部分时,就会发生这种情况。

  • 作为字符串运算符的操作数的参数与其他操作数的聚合类型具有相同的派生类型。如果运算符的所有操作数都是参数,则派生类型为VARCHAR;它的归类由 的值决定 collation_connection

  • DATETIME如果运算符返回 a DATETIMETIME如果运算符返回 a TIME,并且 DATE如果运算 符返回 a ,则 作为时间运算符的操作数的参数具有类型DATE

  • 作为二元比较运算符操作数的参数与比较的另一个操作数具有相同的派生类型。

  • 作为三元比较运算符的操作数的参数,例如BETWEEN具有与其他操作数的聚合类型相同的派生类型。

  • 如果比较运算符的所有操作数都是参数,则每个操作数的派生类型都是 VARCHAR,排序规则由 的值确定 collation_connection

  • CASE作为、 COALESCEIFIFNULL或 中任何一个的输出操作数的参数 NULLIF与运算符的其他输出操作数的聚合类型具有相同的派生类型。

  • 如果 CASE, COALESCE, IF, IFNULL, 或 中任何一个的输出操作数NULLIF都是参数,或者它们都是NULL,则参数的类型由运算符的上下文决定。

  • 如果参数是 、 、 或 中任何一个的操作数 CASECOALESCE()并且 IF没有 IFNULL类型确定上下文,则所涉及的每个参数的派生类型都是VARCHAR,其排序规则由 的值确定 collation_connection

  • 作为 a 的操作数的参数 CAST()与 指定的类型相同CAST()

  • SELECT如果参数是不属于语句 的列表的直接成员, INSERT则参数的派生类型为 VARCHAR,其排序规则由 的值确定 collation_connection

  • SELECT如果参数是作为语句一部分的列表 的直接成员, INSERT则参数的派生类型是参数插入到的相应列的类型。

  • 如果参数用作语句子句或语句子句中赋值的源 , 则 SET参数 的派生类型是or子句更新的相应列的类型。 UPDATEON DUPLICATE KEY UPDATEINSERTSETON DUPLICATE KEY UPDATE

  • 如果参数是函数的参数,则派生类型取决于函数的返回类型。

对于实际类型和派生类型的某些组合,会触发语句的自动重新准备,以确保与以前版本的 MySQL 更紧密地兼容。如果满足以下任何条件,则不会进行重新准备:

  • NULL用作实际参数值。

  • 参数是 a 的操作数 CAST()。(相反,尝试转换为派生类型,如果转换失败则引发异常。)

  • 参数是一个字符串。(在这种情况下,执行隐式 。) CAST(? AS derived_type)

  • 参数的派生类型和实际类型都 INTEGER具有相同的符号。

  • 参数的派生类型是 DECIMAL,其实际类型是DECIMALINTEGER

  • 派生类型是DOUBLE,实际类型是任何数字类型。

  • 派生类型和实际类型都是字符串类型。

  • 如果派生类型是临时的并且实际类型是临时的。例外:派生类型是 TIME,实际类型不是 TIME;派生类型是 DATE,实际类型不是 DATE

  • 派生类型是临时类型,实际类型是数字。

对于刚刚列出的情况以外的情况,重新准备语句并使用实际参数类型而不是派生参数类型。

这些规则也适用于准备好的语句中引用的用户变量。

在准备好的语句中为给定的参数或用户变量使用不同的数据类型,以便在第一次执行之后执行该语句会导致重新准备该语句。这效率较低;它还可能导致参数(或变量)的实际类型发生变化,从而导致结果与准备语句的后续执行不一致。由于这些原因,建议在重新执行准备好的语句时对给定参数使用相同的数据类型。