存储过程的 LAST_INSERT_ID() 结果

Posted

技术标签:

【中文标题】存储过程的 LAST_INSERT_ID() 结果【英文标题】:LAST_INSERT_ID() result from stored procedure 【发布时间】:2013-03-14 21:09:55 【问题描述】:

我在 mysql 中有一个存储过程,它正在更新很多行,然后插入一个(具体来说是分层数据结构)。除了我设置@insert_id 变量的最后一个代码之外,不要看太多代码。

CREATE DEFINER=`root`@`localhost` PROCEDURE `addTaskNextTo`(IN `prev_id` INT, IN `pid` INT, IN `name` VARCHAR(100), IN `type` TINYINT, IN `uid` INT, IN `starting_date` DATE, IN `description` TEXT, OUT `insert_id` INT)
MODIFIES SQL DATA
BEGIN
    SELECT @myRight := rgt FROM tasks WHERE id = prev_id;
    UPDATE tasks SET rgt = rgt + 2 WHERE rgt > @myRight AND pid = pid;
    UPDATE tasks SET lft = lft + 2 WHERE lft > @myRight AND pid = pid;
    INSERT INTO tasks(pid, name, lft, rgt, type, uid, starting_date, description)
          VALUES(pid, name, @myRight + 1, @myRight + 2, type, uid, starting_date, description);
    SET @insert_id = LAST_INSERT_ID();
END

现在,当我从 phpMyAdmin 执行此过程时,它会返回正确的最后一个 id,但是当我从 php 调用它时,它会返回上一个插入行的 id ???可能是什么问题,你有什么更好的方法建议我应该这样做。

这是我从 PHP 中调用它的方式:

$sql = "CALL addTaskNextTo($last_tid, $pid, '$task_name', 0, $uid, '$task_start', '$task_desc', @insert_id)";

这本身就充当了一个 SELECT 查询,我得到 1 列“insert_id”,其中一行的值例如“120”,它是前一个非当前插入行的 ID。

这里是接收 sql 字符串并返回单个值的函数:

public static function get_single_value($sql) 
    global $db;
    $rez = $db->query($sql);
    return !empty($rez) ? mysql_result($rez,0) : false;

【问题讨论】:

您是SELECT @insert_id,还是使用其中一个驱动程序的原生->lastInsertId() 之类的功能? 第一个我得到一个错误“命令不同步;你现在不能运行这个命令”,而原生的只是返回零。存储过程本身具有“insert_id”作为 OUT 参数,我只是在执行“CALL procedureName(var1,var2, ..., @insert_id)”,我将其视为选择查询。 (不是对说,是问如何你找回它;))。您能否发布整个创建过程以及在您的问题中如何调用它? 我已经放置了整个过程和我正在从 PHP 中执行的 sql 字符串 由于是PHP,所以可以使用PHP本身给定的方法获取最后插入ID。 【参考方案1】:

我不知道你是怎么做的,但你应该这样做

$dbh->query("CALL addTaskNextTo($last_tid, $pid, '$task_name', 0, $uid, '$task_start', '$task_desc', @insert_id)");
$dbh->query("SELECT @insert_id"); 

请注意,您需要一个单独的 SELECT 查询来获取插入 ID 的更新值。否则你只会得到旧的。

或者,更好的是,类似:

$stmt = $dbh->prepare("CALL addTaskNextTo(?, ?, ?, ?, ?, ?, ?, @insert_id)");
$stmt->execute(array($last_tid, $pid, $task_name, 0, $uid, $task_start, $task_desc));
$dbh->query("SELECT @insert_id"); 

也可以使用 bind 将输出参数直接放在 PHP 变量中(参见 the third example in manual)。


编辑:如果您收到消息“命令不同步;您现在无法运行此命令”,这意味着您已打开无缓冲查询。这意味着您要么需要在两者之间读取结果,要么使用缓冲查询。为了解决这个问题,您可以在第一个查询之后但在运行下一个查询之前使用$stmt->store_result()。在this thread查看更多详情。

【讨论】:

在调用存储过程后尝试运行任何类型的查询时出现此错误:数据库查询失败:命令不同步;你现在不能运行这个命令

以上是关于存储过程的 LAST_INSERT_ID() 结果的主要内容,如果未能解决你的问题,请参考以下文章

Mysql 在存储过程中使用 LAST_INSERT_ID

MySQL 从存储过程中检索 last_insert_id

MYSQL:存储过程,插入一行,然后通过 LAST_INSERT_ID() 选择它

是否有等效于 LAST_INSERT_ID 的时间戳?

MariaDB 列存储 LAST_INSERT_ID() 替代

我在 php 和 mysql 中使用 LAST_INSERT_ID() 但我无法得到结果。为啥?