更新时MariaDB存储过程重复条目?

时间:2015-12-09 15:51:54

标签: stored-procedures mariadb

我已经编写了一个存储过程来更新并将记录插入MariaDB 15.1版,distrib 10.0.13-MariaDB for Win64(x86)。

我的存储过程:

    exitProc:BEGIN
    #--
    # procCreateUser
    # Parameters:
    #     biPerson_id, the id of the user, NULL if new
    #     vcFirstName, the christian name of the user
    #     vcMiddleName, optional, middle name of the user
    #     vcSurName, the surname of the user
    #     vcEmail, the email associated with the user
    #  biDept, the department ID
    #     biRole, the role ID
    #     vcUsername, the login name of the user
    #     vcPassword, the password for the user
    #     vcIPorHost, the IP address or Host name of the client
    #     biUID, the user ID of the user performing this procedure
    #--
         DECLARE txtAuditEntry     TEXT;
         DECLARE EXIT HANDLER FOR SQLEXCEPTION
              BEGIN
                   GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE,
                   @errno = MYSQL_ERRNO, @text = MESSAGE_TEXT;
                   CALL procLogError(CONCAT("procCreateUser: "
                                                           ,@errno, " (", @sqlstate,         "): ", @text));
              END;         
    #Prepare the parameters
         IF (vcFirstName IS NULL) OR (LENGTH(TRIM(vcFirstName)) = 0) THEN
              CALL procLogError("vcFirstName must be valid");
              LEAVE exitProc;
         ELSEIF (vcSurName IS NULL) OR (LENGTH(TRIM(vcSurName)) = 0) THEN
              CALL procLogError("vcSurName must be valid");
              LEAVE exitProc;
         ELSEIF (vcEmail IS NULL) OR (LENGTH(TRIM(vcEmail)) = 0) THEN
              CALL procLogError("vcEmail must be valid");
              LEAVE exitProc;
         ELSEIF (biDept_id IS NULL) OR (biDept_id = 0) THEN
              CALL procLogError("biDept_id must be valid");
              LEAVE exitProc;
         ELSEIF (biRole_id IS NULL) OR (biRole_id = 0) THEN
              CALL procLogError("biRole_id must be valid");
              LEAVE exitProc;
         ELSEIF (vcUsername IS NULL) OR (LENGTH(TRIM(vcUsername)) = 0) THEN
              CALL procLogError("vcUsername must be valid");
              LEAVE exitProc;
         END IF;
    #Report parameters
         CALL procAuditEntry(CONCAT("biPerson_id: ", biPerson_id),         vcIPorHost, biCreator_id);
         CALL procAuditEntry(CONCAT("vcFirstName: ", vcFirstName),         vcIPorHost, biCreator_id);    
         CALL procAuditEntry(CONCAT("vcMiddleName: ", vcMiddleName), vcIPorHost, biCreator_id);         
         CALL procAuditEntry(CONCAT("vcSurName: ", vcSurName), vcIPorHost, biCreator_id);              
         CALL procAuditEntry(CONCAT("vcEmail: ", vcEmail), vcIPorHost, biCreator_id);                   
         CALL procAuditEntry(CONCAT("biDept_id: ", biDept_id), vcIPorHost, biCreator_id);                        
         CALL procAuditEntry(CONCAT("biRole_id: ", biRole_id), vcIPorHost, biCreator_id);                        
         CALL procAuditEntry(CONCAT("vcUsername: ", vcUsername), vcIPorHost, biCreator_id);                             

         IF (biPerson_id IS NULL) THEN
              CALL procAuditEntry("INSERT", vcIPorHost,         biCreator_id);                             

              INSERT INTO `tbl_people` (
                   `vcFirstName`
                   ,`vcMiddleName`
                   ,`vcSurName`
                   ,`vcEmail`
                   ,`biDept_id`
                   ,`biRole_id`
                   ,`vcUserName`
                   ,`vcPassWord`
              ) VALUES (
                   vcFirstName
                   ,vcMiddleName
                   ,vcSurName
                   ,vcEmail
                   ,biDept_id
                   ,biRole_id
                   ,vcUsername
                   ,vcPassword
              );
    #Create audit log entry    
              SET txtAuditEntry = CONCAT('user \'', vcUsername, '\' created');
              CALL procAuditEntry(txtAuditEntry, vcIPorHost, biCreator_id);
         ELSE
               CALL procAuditEntry("A.UPDATE", vcIPorHost, biCreator_id);

              UPDATE `tbl_people` SET
                   `vcFirstName`=vcFirstName
                   ,`vcMiddleName`=vcMiddleName
                   ,`vcSurName`=vcSurName
                   ,`vcEmail`=vcEmail
                   ,`biDept_id`=biDept_id
                   ,`biRole_id`=biRole_id
                   ,`vcUserName`=vcUsername
              WHERE
                   `biPerson_id`=biPerson_id;

              CALL procAuditEntry("B.UPDATE", vcIPorHost, biCreator_id);

              IF NOT vcPassWord IS NULL THEN    
                   UPDATE `tbl_people` SET
                        `vcPassWord`=vcPassword
                   WHERE
                        `biPerson_id`=biPerson_id;
              END IF;    
    #Create audit log entry    
              SET txtAuditEntry = CONCAT('user \'', vcUsername, '\' updated');
              CALL procAuditEntry(txtAuditEntry, vcIPorHost, biCreator_id);    
         END IF;
    END

所有打电话到' procAuditEntry'实际上只是用于调试,当我调用此过程创建新记录时,我将第一个参数传递为null。

我可以从审计表中看到它将进入该过程的UPDATE部分。问题是,我收到了程序引发的重复密钥错误,我不理解,因为没有创建新条目,只修改了现有条目。表定义如下:

    CREATE TABLE `tbl_people` (
         `biPerson_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Primary key',
         `biCompany_id` BIGINT(20) UNSIGNED NULL DEFAULT NULL COMMENT 'Link to companies table',
         `biDept_id` BIGINT(20) UNSIGNED NULL DEFAULT NULL COMMENT 'Link to department table',
         `biRole_id` BIGINT(20) UNSIGNED NULL DEFAULT NULL COMMENT 'Link to Job title / description',
         `tiActive` TINYINT(4) NOT NULL DEFAULT '1' COMMENT '1=active, 0=not',
         `dtLastLogin` DATETIME NULL DEFAULT NULL COMMENT 'Date/Time of last login',
         `vcFirstName` VARCHAR(48) NOT NULL COMMENT 'First name',
         `vcMiddleName` VARCHAR(48) NULL DEFAULT NULL COMMENT 'Middle name',
         `vcSurName` VARCHAR(48) NOT NULL COMMENT 'Surname',
         `vcEmail` VARCHAR(256) NOT NULL COMMENT 'Email address',
         `vcUserName` VARCHAR(48) NOT NULL COMMENT 'User name',
         `vcPassWord` VARCHAR(32) NOT NULL COMMENT 'Password',
         PRIMARY KEY (`biPerson_id`),
         UNIQUE INDEX `Name` (`vcFirstName`, `vcSurName`),
         UNIQUE INDEX `userName` (`vcUserName`),
         INDEX `active` (`tiActive`),
         INDEX `dept` (`biDept_id`),
         INDEX `company` (`biCompany_id`),
         INDEX `lastLogin` (`dtLastLogin`),
         INDEX `jobrole` (`biRole_id`)
    )
    COMMENT='All timekeeper users'
    COLLATE='latin1_swedish_ci'
    ENGINE=InnoDB
    AUTO_INCREMENT=4;

记录的错误是:

procCreateUser:1062(23000):重复录入' Simon-Platten'关键字'姓名'

真正奇怪的是,如果我在存储过程之外调用UPDATE它就可以工作。

用REPLACE语句替换UPDATE解决了这个问题,只是不确定UPDATE失败的原因。

1 个答案:

答案 0 :(得分:0)

虽然我使用的是更高版本的MariaDB(10.1.x),但问题也必须在10.0.x版中解决。

尝试:

> SELECT VERSION();
+---------------------------+
| VERSION()                 |
+---------------------------+
| 10.1.9-MariaDB-1~wily-log |
+---------------------------+
1 row in set (0.00 sec)

> DROP TABLE IF EXISTS `tbl_people`;
Query OK, 0 rows affected (0.00 sec)

> CREATE TABLE `tbl_people` (
    ->   `biPerson_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->   `vcFirstName` VARCHAR(48) NOT NULL,
    ->   `vcMiddleName` VARCHAR(48) NULL DEFAULT NULL,
    ->   `vcSurName` VARCHAR(48) NOT NULL,
    ->   UNIQUE INDEX `Name` (`vcFirstName`, `vcSurName`)
    -> );
Query OK, 0 rows affected (0.00 sec)

> INSERT INTO `tbl_people`
    -> (`vcFirstName`, `vcMiddleName`, `vcSurName`)
    -> VALUES
    -> ('Simon', 'R.', 'Platten'),
    -> ('Peter', 'F.', 'Lucas');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

> SELECT
    ->   `biPerson_id`,
    ->   `vcFirstName`,
    ->   `vcMiddleName`,
    ->   `vcSurName`
    -> FROM
    ->   `tbl_people`;
+-------------+-------------+--------------+-----------+
| biPerson_id | vcFirstName | vcMiddleName | vcSurName |
+-------------+-------------+--------------+-----------+
|           1 | Simon       | R.           | Platten   |
|           2 | Peter       | F.           | Lucas     |
+-------------+-------------+--------------+-----------+
2 rows in set (0.00 sec)

> DELIMITER //

> DROP PROCEDURE IF EXISTS `sp_test`//
Query OK, 0 rows affected (0.00 sec)

> CREATE PROCEDURE `sp_test`(
    ->   biPerson_id BIGINT UNSIGNED,
    ->   vcFirstName VARCHAR(48),
    ->   vcMiddleName VARCHAR(48),
    ->   vcSurName VARCHAR(48)
    -> )
    -> BEGIN
    ->   UPDATE `tbl_people` SET
    ->     `vcFirstName` = vcFirstName,
    ->     `vcMiddleName` = vcMiddleName,
    ->     `vcSurName` = vcSurName 
    ->   WHERE `biPerson_id` = biPerson_id;
    -> END//
Query OK, 0 rows affected (0.00 sec)

> DELIMITER ;

> CALL `sp_test`(1, 'Simon', 'A.', 'Platten');
ERROR 1062 (23000): Duplicate entry 'Simon-Platten' for key 'Name'

> DELIMITER //

> DROP PROCEDURE IF EXISTS `sp_test`//
Query OK, 0 rows affected (0.00 sec)

> CREATE PROCEDURE `sp_test`(
    ->   `_biPerson_id` BIGINT UNSIGNED,
    ->   `_vcFirstName` VARCHAR(48),
    ->   `_vcMiddleName` VARCHAR(48),
    ->   `_vcSurName` VARCHAR(48)
    -> )
    -> BEGIN
    ->   UPDATE `tbl_people` SET
    ->     `vcFirstName` = `_vcFirstName`,
    ->     `vcMiddleName` = `_vcMiddleName`,
    ->     `vcSurName` = `_vcSurName` 
    ->   WHERE `biPerson_id` = `_biPerson_id`;
    -> END//
Query OK, 0 rows affected (0.00 sec)

> DELIMITER ;

> CALL `sp_test`(1, 'Simon', 'A.', 'Platten');
Query OK, 1 row affected (0.00 sec)

> SELECT
    ->   `biPerson_id`,
    ->   `vcFirstName`,
    ->   `vcMiddleName`,
    ->   `vcSurName`
    -> FROM
    ->   `tbl_people`;
+-------------+-------------+--------------+-----------+
| biPerson_id | vcFirstName | vcMiddleName | vcSurName |
+-------------+-------------+--------------+-----------+
|           1 | Simon       | A.           | Platten   |
|           2 | Peter       | F.           | Lucas     |
+-------------+-------------+--------------+-----------+
2 rows in set (0.00 sec)