Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  PREPARE Statement

15.5.1 预备语句

PREPARE stmt_name FROM preparable_stmt

PREPARE 语句准备一个 SQL 语句,并将其命名为 stmt_name,以便以后引用该语句。该预备语句将使用 EXECUTE 执行,并使用 DEALLOCATE PREPARE 释放。有关示例,请参阅 第 15.5 节,“预备语句”

语句名称不区分大小写。preparable_stmt 是一个字符串文字或用户变量,包含 SQL 语句的文本。该文本必须表示单个语句,而不是多个语句。在语句中,? 字符可以用作参数标记,以指示在执行语句时将绑定到查询的数据值。这些 ? 字符不应被引号括起来,即使您计划将它们绑定到字符串值。

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

预备语句的作用域是创建它的会话,其中有一些含义:

  • 在一个会话中创建的预备语句不可用于其他会话。

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

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

  • 在存储程序上下文中创建的预备语句不能引用存储过程或函数参数或局部变量,因为它们在程序结束时将超出范围,并且在以后执行语句时将不可用。作为解决方法,可以引用用户定义的变量,它们也具有会话作用域;请参阅 第 11.4 节,“用户定义变量”

预备语句中参数的类型是在首次准备语句时确定的;它将保留该类型,直到 EXECUTE 语句执行该预备语句时(除非语句被重新准备,如本节后面所述)。确定参数类型的规则如下:

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

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

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

  • 如果算术运算符没有类型确定上下文,则参与运算的参数的派生类型为 DOUBLE PRECISION。这可能发生在参数是 SELECT 列表的顶级节点时,或者当它是比较运算符的一部分时。

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

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

  • 一个二进制比较运算符的操作数参数的派生类型与比较运算符的另一个操作数相同。

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

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

  • 任何CASECOALESCEIFIFNULLNULLIF的输出操作数参数的派生类型与运算符的其他输出操作数的聚合类型相同。

  • 如果所有输出操作数都是参数,或者它们都是NULL,则参数的类型由运算符的上下文决定。

  • 如果参数是CASECOALESCE()IFIFNULL的操作数,并且没有类型确定上下文,则每个参数的派生类型为VARCHAR,其排序规则由collation_connection的值确定。

  • 一个CAST()的操作数参数的派生类型与CAST()指定的类型相同。

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

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

  • 如果参数用于UPDATE语句的SET子句或INSERT语句的ON DUPLICATE KEY UPDATE子句中,则参数的派生类型是更新的对应列的类型。

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

对于某些实际类型和派生类型的组合,会触发语句的自动重新准备,以确保与之前的 MySQL 版本的兼容性。重新准备不会发生,如果以下任何条件为真:

  • NULL 用作实际参数值。

  • 参数是CAST()的操作数。(相反,尝试将其强制转换为派生类型,并在转换失败时引发异常。)

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

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

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

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

  • 两者都是字符串类型。

  • 如果派生类型是时间类型,实际类型也是时间类型。例外:派生类型是TIME,实际类型不是TIME;派生类型是DATE,实际类型不是DATE

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

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

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

在准备语句的后续执行中,对于给定的参数或用户变量使用不同的数据类型将导致语句被重新准备。这可能会导致效率下降,也可能会导致参数(或变量)的实际类型发生变化,从而导致结果不一致。在准备语句的后续执行中,建议使用相同的数据类型来避免这些问题。