sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo verificar si INSERT salió bien en la función almacenada?

Puede comprobar la función LAST_INSERT_ID() e INSERT IGNORE.

Si INSERT IGNORE fue exitoso, obtendrá la clave principal devuelta. Vamos a crear una tabla con una clave principal 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í está 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, puede comprobar el valor de retorno de la función. Un valor de retorno distinto de cero significa que INSERT IGNORE salió bien. Un valor de retorno cero indica una clave duplicada sin introducir un número de error en mysqld.

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

Probemos otro ejemplo con una configuración de función almacenada diferente usando INSERT y sin usar 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, la función almacenada devuelve 0 si INSERTAR fue correcto y devuelve 1 con una clave duplicada en el nombre. ¿La ventaja? No hay números de identificación desperdiciados para auto_increment. ¿La desventaja? Hacer una declaración SELECT cada vez para verificar que el nombre ya esté presente en la tabla.

Puede elegir de qué manera desea manejar las claves duplicadas. El primer método permite que mysqld maneje la condición de INSERT IGNORE. El segundo método tiene la función almacenada comprobando la clave duplicada primero antes de INSERTAR.