2015-12-09 20 views
0

我寫了一個存儲過程來更新並將記錄插入MariaDB版本15.1,distrib 10.0.13-MariaDB for Win64(x86)。MariaDB存儲過程在更新時重複條目?

我的存儲過程:

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」實際上只是用於調試,當我把這個過程創建一個新的紀錄我傳遞的第一個參數爲空。

我可以從審計表中看到它將進入過程的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):重複的項目 '西蒙 - Platten' 關鍵 '名稱'

的非常奇怪事情是,如果我在存儲過程的外面調用它的UPDATE它工作。

用REPLACE語句替換UPDATE解決了這個問題,只是不確定UPDATE失敗的原因。

+1

避免命名變量和參數等於你的表的列名。 – wchiquito

+0

「UNIQUE INDEX'Name'('vcFirstName','vcSurName'),」在這之前會有多久真的有一個同名的第二個人? –

+0

考慮通過使用'INSERT ... ON DUPLICATE KEY UPDATE ...'來縮短代碼。 –

回答

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) 
+0

您是否澄清這是MariaDB中的問題? – SPlatten

+0

@SPlatten:相反,我正在澄清問題是定義存儲過程的參數的方式。 – wchiquito

+0

@SPlatten:MariaDB文檔在這一點上並不十分明確,但是MySQL文檔在這方面更加明確:請參見[13.6.4.2本地變量作用域和解析](http://dev.mysql.com/doc /refman/5.7/en/local-variable-scope.html)和[C.1限制存儲程序 - >存儲例程中的名稱衝突](https://dev.mysql.com/doc/refman/5.7/en /stored-program-restrictions.html)。 – wchiquito