2011-05-09 46 views

回答

7

您可以檢查LAST_INSERT_ID()函數和INSERT IGNORE。

如果INSERT IGNORE成功,則返回主鍵。我們創建一個帶有自動增量主鍵和名稱上唯一鍵的表格。

use test 
DROP TABLE IF EXISTS nametable; 
CREATE TABLE nametable 
(
    id int not null auto_increment, 
    name varchar(20) not null, 
    primary key (id), 
    unique key (name) 
); 
DELIMITER $$ 
DROP FUNCTION IF EXISTS `test`.`InsertName` $$ 
CREATE FUNCTION `test`.`InsertName` (newname VARCHAR(20)) RETURNS INT 
BEGIN 
    INSERT IGNORE INTO test.nametable (name) VALUES (newname); 
    RETURN LAST_INSERT_ID(); 
END $$ 
DELIMITER ; 
SELECT InsertName('rolando'); 
SELECT InsertName('rolando'); 
SELECT InsertName('pamela'); 
SELECT InsertName('pamela'); 
SHOW CREATE TABLE test.nametable\G 
SELECT * FROM test.nametable; 

這裏是例如正在運行:

mysql> use test 
Database changed 
mysql> DROP TABLE IF EXISTS nametable; 
Query OK, 0 rows affected (0.04 sec) 

mysql> CREATE TABLE nametable 
    -> (
    -> id int not null auto_increment, 
    -> name varchar(20) not null, 
    -> primary key (id), 
    -> unique key (name) 
    ->); 
Query OK, 0 rows affected (0.07 sec) 

mysql> DELIMITER $$ 
mysql> DROP FUNCTION IF EXISTS `test`.`InsertName` $$ 
Query OK, 0 rows affected (0.00 sec) 

mysql> CREATE FUNCTION `test`.`InsertName` (newname VARCHAR(20)) RETURNS INT 
    -> BEGIN 
    -> INSERT IGNORE INTO test.nametable (name) VALUES (newname); 
    -> RETURN LAST_INSERT_ID(); 
    -> END $$ 
Query OK, 0 rows affected (0.00 sec) 

mysql> DELIMITER ; 
mysql> SELECT InsertName('rolando'); 
+-----------------------+ 
| InsertName('rolando') | 
+-----------------------+ 
|      1 | 
+-----------------------+ 
1 row in set (0.03 sec) 

mysql> SELECT InsertName('rolando'); 
+-----------------------+ 
| InsertName('rolando') | 
+-----------------------+ 
|      0 | 
+-----------------------+ 
1 row in set (0.02 sec) 

mysql> SELECT InsertName('pamela'); 
+----------------------+ 
| InsertName('pamela') | 
+----------------------+ 
|     3 | 
+----------------------+ 
1 row in set (0.02 sec) 

mysql> SELECT InsertName('pamela'); 
+----------------------+ 
| InsertName('pamela') | 
+----------------------+ 
|     0 | 
+----------------------+ 
1 row in set (0.03 sec) 

mysql> SHOW CREATE TABLE test.nametable\G 
*************************** 1. row *************************** 
     Table: nametable 
Create Table: CREATE TABLE `nametable` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(20) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `name` (`name`) 
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 
1 row in set (0.00 sec) 

mysql> SELECT * FROM test.nametable; 
+----+---------+ 
| id | name | 
+----+---------+ 
| 3 | pamela | 
| 1 | rolando | 
+----+---------+ 
2 rows in set (0.00 sec) 

mysql> 

如在前面的示例中所示,可以檢查該函數的返回值。非零返回值意味着INSERT IGNORE進展順利。零返回值表示重複密鑰,但不會向mysqld引入錯誤編號。

此方法的缺點是您無法返回並使用id 2和4,因爲在重複密鑰的情況下嘗試插入IGNORE失敗。

讓我們嘗試使用插入不同存儲功能設置,並且不使用LAST_INSERT_ID()又如:

use test 
DROP TABLE IF EXISTS nametable; 
CREATE TABLE nametable 
(
    id int not null auto_increment, 
    name varchar(20) not null, 
    primary key (id), 
    unique key (name) 
); 
DELIMITER $$ 
DROP FUNCTION IF EXISTS `test`.`InsertName` $$ 
CREATE FUNCTION `test`.`InsertName` (newname VARCHAR(20)) RETURNS INT 
BEGIN 
    DECLARE rv INT; 
    SELECT COUNT(1) INTO rv FROM test.nametable WHERE name = newname; 
    IF rv = 0 THEN 
    INSERT INTO test.nametable (name) VALUES (newname); 
    END IF; 
    RETURN rv; 
END $$ 
DELIMITER ; 
SELECT InsertName('rolando'); 
SELECT InsertName('rolando'); 
SELECT InsertName('pamela'); 
SELECT InsertName('pamela'); 
SHOW CREATE TABLE test.nametable\G 
SELECT * FROM test.nametable; 

下面是結果:

mysql> use test 
Database changed 
mysql> DROP TABLE IF EXISTS nametable; 
Query OK, 0 rows affected, 1 warning (0.00 sec) 

mysql> CREATE TABLE nametable 
    -> (
    -> id int not null auto_increment, 
    -> name varchar(20) not null, 
    -> primary key (id), 
    -> unique key (name) 
    ->); 
Query OK, 0 rows affected (0.10 sec) 

mysql> DELIMITER $$ 
mysql> DROP FUNCTION IF EXISTS `test`.`InsertName` $$ 
Query OK, 0 rows affected (0.00 sec) 

mysql> CREATE FUNCTION `test`.`InsertName` (newname VARCHAR(20)) RETURNS INT 
    -> BEGIN 
    -> DECLARE rv INT; 
    -> SELECT COUNT(1) INTO rv FROM test.nametable WHERE name = newname; 
    -> IF rv = 0 THEN 
    ->  INSERT INTO test.nametable (name) VALUES (newname); 
    -> END IF; 
    -> RETURN rv; 
    -> END $$ 
Query OK, 0 rows affected (0.00 sec) 

mysql> DELIMITER ; 
mysql> SELECT InsertName('rolando'); 
+-----------------------+ 
| InsertName('rolando') | 
+-----------------------+ 
|      0 | 
+-----------------------+ 
1 row in set (0.04 sec) 

mysql> SELECT InsertName('rolando'); 
+-----------------------+ 
| InsertName('rolando') | 
+-----------------------+ 
|      1 | 
+-----------------------+ 
1 row in set (0.00 sec) 

mysql> SELECT InsertName('pamela'); 
+----------------------+ 
| InsertName('pamela') | 
+----------------------+ 
|     0 | 
+----------------------+ 
1 row in set (0.03 sec) 

mysql> SELECT InsertName('pamela'); 
+----------------------+ 
| InsertName('pamela') | 
+----------------------+ 
|     1 | 
+----------------------+ 
1 row in set (0.00 sec) 

mysql> SHOW CREATE TABLE test.nametable\G 
*************************** 1. row *************************** 
     Table: nametable 
Create Table: CREATE TABLE `nametable` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(20) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `name` (`name`) 
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 
1 row in set (0.00 sec) 

mysql> SELECT * FROM test.nametable; 
+----+---------+ 
| id | name | 
+----+---------+ 
| 2 | pamela | 
| 1 | rolando | 
+----+---------+ 
2 rows in set (0.00 sec) 

mysql> 

在這個例子中,存儲的函數返回如果INSERT正確,則返回0,並返回1,並在名稱上使用重複鍵。優勢? auto_increment沒有浪費的id號碼。缺點?每次執行SELECT語句以檢查表中已存在的名稱。

您可以選擇想要處理重複鍵的方式。第一種方法可以讓mysqld處理INSERT IGNORE的情況。第二種方法是存儲函數在INSERT之前首先檢查重複鍵。

+0

mysql文件說錯誤的情況下LAST_INSERT_ID()的值是未定義http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id – dancl 2013-06-26 22:20:41

0

存儲過程是「全有或全無」的

因此,如果您在存儲過程的一個INSERT,並且INSERT失敗上的重複鍵錯誤,整個存儲過程都將回滾。

如果sproc無誤地執行,您可以確信INSERT沒有錯誤。現在,這並不意味着INSERT實際上發生只是因爲存儲過程的完成,只是沒有錯誤....舉例來說,如果你有一些WHERE條款,排除了INSERT但不會引發錯誤那麼可能會有一些含糊之處。

相關問題