DAM - DAW - MP 0484 Bases de Dades - NF4
Quan executem una comanda FETCH o SELECT ... INTO ... i aquesta no retorna cap fila, es produeix el següent error:
ERROR 1329 (02000): No data - zero rows fetched, selected, or processed
L'error, en una instrucció SELECT ... INTO ..., produeix un warning
+------+----------+-----------------------------------------------------+
| Code | SQLSTATE | Description |
+------+----------+-----------------------------------------------------+
| 1329 | '02000' | No data - zero rows fetched, selected, or processed |
+------+----------+-----------------------------------------------------+
El que fem és capturar aquest error, canviar el valor d'una variable que controla la finalització dels FETCH i continuar amb la següent instrucció. Això ho fem amb l'ajuda dels HANDLERs.
Podeu consultar els codis d'error a la pàgina de codis d'error de MariaDB.
A part del codi d'error, podem utilitzar paraules més globals:
-
SQLWARNING -
NOT FOUND -
SQLEXCEPTION
HANDLER
En MariaDB i MySQL també podem gestionar les excepcions que rebem a meitat del codi. Per això caldrà:
- declarar un handler que gestionarà l'error que volguem capturar. Ho farem a la part de la declaració de variables
La instrucció DECLARE ... HANDLER especifica el gestors (handler) que pot fer front a una condició.
DECLARE handler_type HANDLER
FOR condition_value [, condition_value] ...
statement
handler_type: condition_value:
CONTINUE SQLSTATE [VALUE] sqlstate_value
| EXIT | condition_name
| UNDO | SQLWARNING
| NOT FOUND
| SQLEXCEPTION
| mariadb_error_code
Si es presenta una d'aquestes condicions, s'executa la instrucció especificada a statement. La instrucció pot ser una instrucció senzilla (per exemple, SET var_name = valor), o pot ser una instrucció composta escrita mitjançant BEGIN i END.
Molt sovint executem una sola instrucció que posa una variable a TRUE o a 0.
D'aquesta manera, després de l'execució que pot donar error, podem saber si ha anat bé o no.
Els Handlers cal declarar-los després de les variables locals, de les CONDITION i dels cursors.
Amb un exemple ho veurem més clar. Anem a modificar el procediment ADD_FEINA per tal que, si ja existeix el Job que volem inserir, capturem l'error i el tractem nosaltres.
Què passa si intentem crear dos feines iguals? La segona dóna el següent error:
SQL Error [1062] [23000]: (conn=12) Duplicate entry 'IT_DBA' for key 'PRIMARY'
Cal fixar-nos en el codi d'error SQL Error [1062] [23000]. Per tant analitzarem el següent codi:
CREATE OR REPLACE PROCEDURE ADD_FEINA(
p_job_id TYPE OF jobs.job_id,
p_job_title TYPE OF jobs.job_title
)
BEGIN
DECLARE v_ok BOOLEAN DEFAULT TRUE;
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET v_ok = FALSE;
INSERT INTO FEINES(job_id, job_title)
VALUES(UPPER(p_job_id), p_job_title);
IF NOT v_ok THEN
SELECT 'ERROR: Feina ja existent';
END IF;
END;
En aquest exemple és imporant, també, el CONTINUE ja que indica al SGBD que després de gestionar l'error, continuï amb la següent instrucció que ha provocat el llançament del Handler. L'alternativa és un EXIT que provocaria la finalització del bloc de codi, en el nostre cas, del Procediment.
Podem reprogramar la funció nomDepartament de la següent forma:
DELIMITER //
CREATE OR REPLACE FUNCTION nomDepartament(
p_department_id TYPE OF empresa.departments.department_id
)
RETURNS VARCHAR(100)
BEGIN
DECLARE v_department_name TYPE OF empresa.departments.department_NAME;
DECLARE EXIT handler FOR NOT FOUND RETURN 'Departament INEXISTENT';
SELECT department_name INTO v_department_name
FROM empresa.departments
WHERE department_id = p_department_id;
RETURN v_department_name;
END;
//
DELIMITER ;
DECLARE CONDITION
La instrucció DECLARE CONDITION defineix una condició d'error amb un nom.
Especifica una condició que necessita un HANDLER específic i associa un nom a aquesta condició.
Més endavant, el nom es pot utilitzar en una instrucció DECLARE .. HANDLER, SIGNAL o RESIGNAL sempre que la sentència estigui situada al mateix bloc BEGIN .. END.
Les declaracions de condicions (DECLARE CONDITION) han d'aparèixer abans que les declaracions de cursors i de handlers.
Un condition_value per DECLARE CONDITION pot ser un valor mysql SQLSTATE (una cadena de 5 caràcters literal) o un codi d'error MySQL (un nombre).
No heu d'utilitzar el valor de mysqlSTATE '00000' o el codi d'error MySQL 0, perquè
indiquen que la sentència ha anat bé.
Si especifiqueu un valor SQLSTATE no vàlid, es produeix un error com aquest:
ERROR 1407 (42000): Bad SQLSTATE: '00000'
La sintaxi de la comanda DECLARE CONDITION és:
DECLARE condition_name CONDITION FOR condition_value
condition_value:
SQLSTATE [VALUE] sqlstate_value
| mysql_error_code
L'ús de noms per a condicions pot ajudar a fer més clar el codi de programa emmagatzemat. Per exemple, a l'exemple següent aplicarem un gestor als intents d'eliminar (DROP) una taula inexistent, però això només és evident si sap que 1051 és el codi d'error MariaDB per a unknown table:
En aquest exemple es captura l'error 1051 i s'executa un codi per continuar després de l'error, a la següent instrucció que ha provocat l'error.
DECLARE CONTINUE HANDLER FOR 1051
BEGIN
-- cos del codi a executar en cas de produir-se l'error
END;
En aquest exemple es defineix primer la condició amb un nom i després es declara el handler que capturarà l'error i executarà él bloc de codi.
DECLARE no_existeix_taula CONDITION FOR 1051;
DECLARE CONTINUE HANDLER FOR no_existeix_taula
BEGIN
-- cos del codi a executar en cas de produir-se l'error
END;
-
Una condició també pot basar-se en l'
SQLSTATE.DECLARE no_existeix_taula CONDITION FOR SQLSTATE '42S02'; DECLARE CONTINUE HANDLER FOR no_existeix_taula BEGIN -- cos del codi a executar en cas de produir-se l'error END;
Les CONDITION cal declarar-les abans que els CURSOR.
Exemple
DELIMITER //
BEGIN NOT ATOMIC
DECLARE no_existeix CONDITION FOR 1329;
DECLARE v_department_name TYPE OF departments.department_name;
DECLARE CONTINUE HANDLER FOR no_existeix SET v_department_name = "INEXISTENT";
SET @id = 1100;
SELECT department_name INTO v_department_name
FROM departments
WHERE DEPARTMENT_ID = @id;
SELECT v_department_name;
END;
//
DELIMITER ;