Mysql 在存储过程中使用 LAST_INSERT_ID

Posted

技术标签:

【中文标题】Mysql 在存储过程中使用 LAST_INSERT_ID【英文标题】:Mysql use LAST_INSERT_ID in stored procedure 【发布时间】:2012-07-19 15:29:21 【问题描述】:

我需要根据插入另一个主表的最后一个 id 创建一个表,为此我创建了以下存储过程:

CREATE PROCEDURE `sp_create_campaign`
(
        IN  p_vName         VARCHAR(70),
        IN  p_iIdOper       INT(11),
        IN  p_iIdCount      INT(11),
        IN  p_iIdMoney      INT(11),
        IN  p_cPrefix       CHAR(2),
        IN  p_tComment      TINYTEXT,
        IN  p_iIdUser       VARCHAR(32),
        OUT p_return_code   TINYINT UNSIGNED
)
BEGIN

    DECLARE p_campaign INT(11);

    DECLARE exit handler for sqlexception
    BEGIN
        -- ERROR
            set p_return_code = 1;
            rollback;
    END;

    DECLARE exit handler for sqlwarning
    BEGIN
            -- WARNING
            set p_return_code = 2;
            rollback;
    END;

    START TRANSACTION;

        -- Campaign
        INSERT INTO `db_campaign` 
            (`vName`, `iIdOper`, `iIdCount`, `iIdMoney`, `cPrefix`, `tComment`, `iIdUser`, `dRegister`)
            VALUES
            (p_vName, p_iIdOper, p_iIdCount, p_iIdMoney, p_cPrefix, p_tComment, p_iIdUser, NOW());

        SET p_campaign := LAST_INSERT_ID();

        -- Sales
        SET @s = CONCAT('DROP TABLE IF EXISTS ', 'db_sale_', p_campaign);
        PREPARE stm FROM @s;
        EXECUTE stm;

        SET @x = CONCAT(
                'CREATE TABLE ',
                'db_sale_', p_campaign,
                "(
                `iIdSale`           INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
                `dDate`             DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
                `dSubtotal`         DECIMAL(7,2) UNSIGNED NOT NULL DEFAULT '00.00',
                `dTax`              DECIMAL(7,2) UNSIGNED NOT NULL DEFAULT '00.00',
                `dTotal`            DECIMAL(7,2) UNSIGNED NOT NULL DEFAULT '00.00',
                `iIdMoney`          INT(11) UNSIGNED NOT NULL,
                `iIdOper`           INT(11) UNSIGNED NOT NULL,
                `iIdBankCount`      INT(11) UNSIGNED NOT NULL,
                `iIdGroup`          INT(11) UNSIGNED NOT NULL,
                `iIdUser`           INT(11) UNSIGNED NOT NULL,
                `iIdUserReg`        VARCHAR(32) NOT NULL,
                `dRegister`         DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
                PRIMARY KEY (`iIdSale`)
                ) ENGINE=MyISAM DEFAULT CHARSET=utf8;");        

        PREPARE stm FROM @x;
        EXECUTE stm;

    COMMIT;

    -- SUCCESS
    set p_return_code = 0;

END

但问题是只插入第一条记录,建表失败。我哪里失败了?

【问题讨论】:

它有没有抛出任何错误? select p_return_code; 的输出是什么?或评论sqlexception handler 块,看看会发生什么。 我评论了 SQLException 并在末尾添加了:“SELECT p_return_code”。但是我什么都不退!仅:“时间:0.000ms 程序成功执行受影响的行:0” 【参考方案1】:

替换此行:SET p_campaign := LAST_INSERT_ID();

有了这个:SELECT LAST_INSERT_ID() INTO p_campaign ;

【讨论】:

【参考方案2】:

如果您使用SET,则需要= 而不是:=

【讨论】:

【参考方案3】:

两件事:

    执行DROP 将隐含COMMIT 您的交易。

    尝试添加

    DEALLOCATE PREPARE stm;

在每个EXECUTE 语句之后。

【讨论】:

我得到了同样的结果。主要问题是获取最后一个 ID。我正在使用相同的存储过程将其他记录直接插入到最新的 ID 中,但仍然无法正常工作。会用于交易吗? 如果 db_campaign 是 MyISAM,您可以删除 START TRANSACTION;COMMIT;ROLLBACK;s,因为它们实际上是 NOOP。您可以添加一些日志记录,例如 INSERT INTO syslog SET script='myscript', line='lineno', message=CONCAT('last_insert_id()=', LAST_INSERT_ID()); 是的,你是对的。调查 MyISAM 数据库不支持事务。【参考方案4】:

根据last_insert_id()的mysql文档

如果存储过程执行更改 LAST_INSERT_ID() 值的语句,则更改后的值会被过程调用之后的语句看到。

使用类似的东西:

SELECT id INTO p_campaign FROM db_campaign ORDER BY id DESC LIMIT 1;

或者:

SELECT max(id) INTO p_campaign FROM db_campaign;

【讨论】:

以上是关于Mysql 在存储过程中使用 LAST_INSERT_ID的主要内容,如果未能解决你的问题,请参考以下文章

怎么在mysql中查询已建立的存储过程

如何在 Google App Script 中使用参数调用 MySQL 存储过程?

MySQL 存储过程,获取使用游标查询的结果集

mysql 存储过程总结(一)

mysql存储过程中怎么在循环中取变量值???

Mysql:在mysql视图中调用mysql存储过程函数