如何从 PHP 在 mySQL 中插入/创建存储过程?

Posted

技术标签:

【中文标题】如何从 PHP 在 mySQL 中插入/创建存储过程?【英文标题】:How to insert/create stored procedures in mySQL from PHP? 【发布时间】:2011-06-02 07:48:06 【问题描述】:

我使用 mysql Workbench 制作了许多存储过程。当使用 MySQL 工作台将它们放入我的测试数据库时,它们工作得很好。

现在我正在准备用于部署的数据库创建脚本,这是唯一给我带来麻烦的脚本。当我使用命令行/mysql shell 时,脚本运行得非常好。只有当我使用 php mysql(i) 接口来执行脚本时——它才会失败。不加评论。

我使用 MySQL 工作台为我生成的过程创建脚本;也就是说,它有这样的模式:

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

在脚本的开头,然后对每个过程重复:

DELIMITER $$
USE `dbname`$$
CREATE PROCEDURE `procname`(IN inputparameters)
BEGIN

...程序在这里

;
END$$
DELIMITER ;

如果从 MySQL Workbench 运行,此脚本可以正常工作。如果我从 mysql 命令行尝试相同的操作,它也运行良好。但是当我通过 PHP mysqli 接口执行它时它无法完成任何事情(使用 mysqli_multi_query 执行它,这对于创建和填充数据库的其他脚本来说很好)。界面上没有返回错误,没有结果(!)。 我得到的只是“假”,仅此而已。错误代码为 0,没有错误信息。

对我来说这是一个很大的 WTF,我希望你能指出我正确的方向 - 我该如何解决这个问题并从 PHP 安装程序?

PS:root/admin 访问权限已提供并验证(毕竟,我只是使用相同的连接创建了数据库、创建了用户、插入了表等等)。

【问题讨论】:

尝试删除使用'dbname'。如果使用 mysqli_query 命令,也可以尝试运行。 我确实删除了那个 USE 语句,没有效果。 mysqli_query 也失败了——在这种情况下,原因很明显:字符串包含多个语句,所以如果它正在正确执行,它将返回多个结果——mysqli_query 无法处理。 - 对于其他脚本,mysqli_multi_query 工作得非常好,为每个语句返回一个结果行。 (成功时为空行,注意:1051 行作为对 SHOW WARNINGS 的反应; - 全部符合预期)。 我越来越接近 - 没有解决方案,但诊断。 DELIMITER 似乎是在客户端实现的 (!)。 您是否在双引号字符串中指定查询? PHP 可能会将$$ 作为变量变量吃掉。 不,它们存储在我直接从文件中读取的字符串中,我检查了 $$ 替换。 【参考方案1】:

DELIMITER 是 mysql 客户端应用程序实际使用的东西。我相信客户端应用程序负责分解它发送到 Mysql 的查询。例如,这就是 PHPMyAdmin 所做的。

与其花一整夜编写脚本来将 MySQL 解析为查询,不如使用我编写的代码。您可以在 scriptToQueries 函数中找到它,这里:

http://wush.net/svn/luckyapps/pie/trunk/framework/classes/Db/Mysql.php

享受

编辑:自从写下这个答案后,我已将代码移植到免费的 Q 平台中,您可以在其中学习代码:https://github.com/EGreg/Platform/blob/master/platform/classes/Db/Mysql.php#L824

【讨论】:

该链接引用了.htaccess/.htpasswd 密码保护页面。【参考方案2】:

总结一下:

DELIMITER 是在客户端而不是服务器端实现的。

如果您有一个好的驱动程序或 API,它可能会解决这个问题。 PHP mysql / mysqli,到目前为止,不要。

如果您需要使用不同的分隔符(例如,因为默认分隔符出现在脚本中),您必须自己编码/转义您的 SQL 或将其分解,这样您就不需要更改分隔符。这里没有 PHP 的帮助。

【讨论】:

【参考方案3】:

我还没有测试过,但我不会对 mysqli_multi_query() 期望每个查询具有相同的分隔符感到惊讶。 尝试在单个查询中打包存储过程创建,而不使用 DELIMITER 修饰符?

所以不是

<?php
$results = mysqli_multi(
    'DELIMITER $$
    USE `dbname`$$
    CREATE PROCEDURE `procname`(IN inputparameters)
    BEGIN
    ... procedure goes here

    ;
    END$$
    DELIMITER ;
');
?>

就这样做

<?php
$result = mysqli_query('CREATE PROCEDURE `procname`(IN inputparameters) BEGIN ...; END');

告诉我们它是否有效:)

【讨论】:

那行得通,有点。正如我之前写的,DELIMITER 似乎是在客户端实现的,PHP mysql(i) 接口似乎缺少 mySQL 客户端实现的某些部分——比如 DELIMITER。它似乎根本没有实现 DELIMITER。因此,单独发送程序且不使用 DELIMITER 即可。但是,我不认为一次又一次地手动重写例程是一个可行的解决方案。套路挺多的,以后还会有更多。我需要的东西我提供的工具一起工作,而不是重复。但是感谢您的想法,这可能对其他人有所帮助。 谢谢,我遇到了同样的问题,尝试从 mysqli_multi_query 创建和执行存储过程,它在 HeidiSQL 中工作,但是当我从 PHP 执行相同的代码时,它抛出了一个错误。我删除了我的 DELIMETER 语句和任何换行符,它运行良好。谢谢! :D 问题:如何从 PHP 中检查 storedProcedure 是否已经存在? @MikeWarren:SHOW PROCEDURE STATUS 给出了存储过程的列表。

以上是关于如何从 PHP 在 mySQL 中插入/创建存储过程?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PHP 从 MySQL 数据库中存储和检索图像?

如何使用 PHP 和 MYSQL 在单个单元格数据库中插入/存储多个项目

如何从 MySQL 数据库中存储和检索图像并使用 Php 将其显示在 html 中? [复制]

PHP Mysql仅在提交后插入

如何使用 PHP 在 MYSQL 中的数据库表中插入、更新、删除记录时创建日志

使用 PDO 从 php 页面将具有更多列的表单数据插入 mysql 数据库