2011-05-09 13 views
7

Estoy creando una función almacenada que debe insertar una nueva fila en la tabla. En esta tabla también hay una columna única.¿Cómo comprobar si INSERT funcionó bien en la función almacenada?

¿Cómo puedo comprobar si todo va bien y realmente se insertó la fila?

¿Cómo puedo comprobar exactamente que se ha encontrado esta columna única (por ejemplo, intente agregar un valor duplicado)?

Respuesta

7

Puede verificar la función LAST_INSERT_ID() e INSERTAR IGNORE.

Si INSERT IGNORE fue exitoso, obtiene la clave primaria devuelta. Creemos una tabla con una clave primaria de incremento automático y una clave única en un nombre.

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; 

Aquí es el ejemplo que se está ejecutando:

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> 

Como se muestra en el ejemplo anterior, se puede comprobar el valor de retorno de la función. Un valor de retorno distinto de cero significa que INSERT IGNORE fue bien. Un valor de retorno cero indica una clave duplicada sin introducir un número de error en el mysqld.

El inconveniente de este enfoque es que no puede volver atrás y usar los identificadores 2 y 4 debido a intentos fallidos de INSERTAR IGNORAR en el caso de una clave duplicada.

Probemos otro ejemplo con una configuración de función almacenada diferente utilizando INSERT y sin utilizar 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; 

aquí está el resultado:

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> 

En este ejemplo, los retornos de función almacenados 0 si INSERT fue correcto, y devuelve 1 con una clave duplicada en el nombre. ¿La ventaja? No hay números de identificación perdidos para auto_increment. ¿La desventaja? Hacer una instrucción SELECT cada vez para verificar el nombre que ya está presente en la tabla.

Tiene la opción de elegir la forma de manejar claves duplicadas. El primer método permite a mysqld manejar la condición de INSERT IGNORE. El segundo método tiene la función almacenada que verifica la clave duplicada primero antes de INSERTAR.

+0

el doc de mysql dice que el valor de LAST_INSERT_ID() no está definido en el caso de error http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_last-insert-id – dancl

0

procedimientos almacenados son "todo o nada"

Por lo tanto, si se incluye un INSERT en el procedimiento almacenado, y que INSERT falla en un error de clave duplicada, todo el procedimiento almacenado se revertirán.

Si el sproc se ejecuta sin error, puede estar seguro de que el INSERT no tuvo un error. Ahora bien, esto no significa significa que el INSERT realidad sucede sólo porque el sproc completa, sólo que no hubo errores .... por ejemplo, si había alguna WHERE cláusula que excluya el INSERT pero no tira un error entonces puede haber algo de ambigüedad.

Cuestiones relacionadas