Alguien me echa una mano con PL/SQL por favor?

Muy buenas, no se si éste es el mejor sitio para hacer preguntas acerca de programación, pero como he visto varias y nadie se queja, voy para allá.

Os cuento, mi idea es hacer un procedimiento almacenado, que mediante un cursor, seleccione información de distintas tablas, y meta los datos obtenidos en otra tabla, mediante un insert.
La tabla destino se compone de 11 campos obtenidos de éste modo, más uno que se obtiene de una secuencia. Os dejo lo que he hecho para intentar solucionarlo:
------ Procedimiento para generar recibos de cada alumno matriculados end cada servicio
CREATE OR REPLACE PROCEDURE Pr_Genera_Recibos
IS
    v_Alumno_id   Recibos_vigentes.ALUMNO_ID%TYPE;
    v_Alumno_nom  Recibos_vigentes.ALUMNO_NOM%TYPE;
    v_Alumno_ape  Recibos_vigentes.ALUMNO_APE%TYPE;
    v_Tutor_id    Recibos_vigentes.TUTOR_ID%TYPE;
    v_Tutor_nom   Recibos_vigentes.TUTOR_NOM%TYPE;
    v_Tutor_ape   Recibos_vigentes.TUTOR_APE%TYPE;
    v_Serv_id     Recibos_vigentes.SERV_ID%TYPE;
    v_Serv_nom    Recibos_vigentes.SERV_NOM%TYPE;
    v_Serv_Coste  Recibos_vigentes.SERV_COSTE%TYPE;
    v_Nro_banco   Recibos_vigentes.NRO_BANCO%TYPE;
    v_Nro_cuenta  Recibos_vigentes.NRO_CUENTA%TYPE;
   
-- Cursor que selecciona los datos del recibo de todos los campos necesarios para la tabla de recibo. Con los INNER JOIN nos aseguramos de que solo recoja una ocurrencia para cada registro de la tabla Alumno_Servicio_Cuenta
    CURSOR c_Matriculas IS
        SELECT a.Alumno_id, a.nombre, a.Apellidos, t.Tutor_id, t.Nombre, t.apellidos, s.Servicio_id, s.Nombre, s.Precio_mes, a_s_c.Nro_banco, a_s_c.Nro_cuenta
        FROM Alumno_Servicio_Cuenta a_s_c INNER JOIN Alumno a ON a_s_c.Alumno_id = a.Alumno_id INNER JOIN Tutor t ON a.Tutor_id = t.Tutor_id INNER JOIN Servicio s ON a_s_c.Servicio_id = s.Servicio_id;

BEGIN
    DBMS_OUTPUT.PUT_LINE("Generando recibos...");
    DBMS_OUTPUT.PUT_LINE("");
   
    OPEN c_Matriculas;
    FETCH c_Matriculas INTO v_Alumno_id, v_Alumno_nom, v_Alumno_ape, v_Tutor_id, v_Tutor_nom, v_Tutor_ape, v_Serv_id, v_Serv_nom, v_Serv_Coste, v_Nro_banco, v_Nro_cuenta;
   
    LOOP
        INSERT INTO Recibos_vigentes(Recibo_id, Alumno_id, Alumno_nom, Alumno_ape, Tutor_id, Tutor_nom, Tutor_ape, Serv_id, Serv_nom, Serv_Coste, Nro_banco, Nro_cuenta)
            VALUES(Id_Recibo.NEXTVAL, v_Alumno_id, v_Alumno_nom, v_Alumno_ape, v_Tutor_id, v_Tutor_nom, v_Tutor_ape, v_Serv_id, v_Serv_nom, v_Serv_Coste, v_Nro_banco, v_Nro_cuenta);
       
        FETCH c_Matriculas INTO v_Alumno_id, v_Alumno_nom, v_Alumno_ape, v_Tutor_id, v_Tutor_nom, v_Tutor_ape, v_Serv_id, v_Serv_nom, v_Serv_Coste, v_Nro_banco, v_Nro_cuenta;
   
        EXIT WHEN c_Matriculas%NOTFOUND;
    END LOOP;
   
    CLOSE c_Matriculas;
    DBMS_OUTPUT.PUT_LINE("Recibos generados");
   
END;
/


Ejecuto el procedimiento él solo (con todos los demás elementos generados de antemano), y me tira el siguiente error.

00:22:27.437   DBMS   GLOBAL -- Error:  ORA-00604: error producido a nivel 1 de SQL recursivo
00:22:27.484   DBMS   GLOBAL -- ORA-01400: no se puede realizar una inserción NULL en ("SYS"."OBJ$"."NAME"), Batch 1 Line 1 Col 1


la SELECT que usa el cursor funciona a la perfección, y al ver que decía "no se puede realizar una inserción blablabla..." he probado a comentar la sentencia INSERT completa, pero sigo obteniendo exactamente el mismo error, y tampoco se trata de un error provocado por confundirme de nombres de tablas o algo así, porque entonces no tiraría esos errores tan raros.

Además, como podéis ver, me lo suelta en la línea 1 columna 1, así que ando sin siquiera un indicio de por dónde van los tiros. Alguien tiene idea de dónde puede andar el problema?


EDITO: Parece que el ORA-01400 se produce al intetnar insertar un nulo en un campo que no los admite, pero sigue dandolo al comentar el INSERT, además... ¿Qué tabla es "SYS"."OBJ$"."NAME"? :-?
Iba a decir que no veo de dónde sale Id_Recibo.NEXTVAL (yo de PL ni idea, que conste), pero si dices que quitando el insert sigue saliendo el error entonces ya si que no se.
Parece que estas intentando guardar un dato NULL en un campo NOT NULL. Comprueba todos los campos de Recibos_vigentes a ver si hay algún NOT NULL que no debería serlo.
Prueba poniendolo entre parentesis.


FETCH c_Matriculas INTO (v_Alumno_id, v_Alumno_nom, v_Alumno_ape, v_Tutor_id, v_Tutor_nom, v_Tutor_ape, v_Serv_id, v_Serv_nom, v_Serv_Coste, v_Nro_banco, v_Nro_cuenta)

Te falta un COMMIT despues del INSERT.

Asegurate que la tabla destino no tenga un NOT NULL.

Por lo demas nunca me ha gustado abrir cursores asi.
joder, me encanta Oracle y lo bien que se explica con los mensajes de error. Mi hipótesis era la misma, pero claro, si los valores eran todos del tipo de la tabla a la que iba a hacer el insert, no tenía sentido que se quejase. Me volví loco y cuerdo un par de veces, para al final, en lo más profundo de Google, descubrí que era POR PONER DOBLES COMILLAS para los literales en los DBMS_OUTPUT.PUT_LINE !!! [enfado1]

kornshell Id_Recibo.NEXTVAL es una secuencia. De estilo de un autonumérico, pero que se maneja a mano.

Txukie cómo me recomiendas abrir el cursor entonces?

Ah, y gracias a todos por echar una mano. :)
Yo lo suelo hacer sin FETCH

DECLARE

cursor c_tko
IS
select CONTR_NR
, CONTRACT_NR 
, CONTR_BSCS_ID             
, CONTR_CGA_ID               
, HIST_FROM_DT               
, HIST_FROM_DT_NR           
, HIST_STATUS               
, HIST_TO_DT
, previous_hist_to_dt
, next_hist_from_dt 
, next_hist_from_dt_nr 
, ranking_desc
, contr_action_descr
from STT.C_TKO_TEMP
order by CONTR_NR, CONTR_BSCS_ID , HIST_FROM_DT , HIST_TO_DT;


BEGIN

FOR c_tko_rec IN c_tko LOOP

......................

END LOOP





c_tko_rec es un recordset del cual puedes leer la informacion de tu cursor. No necesitas cerrarlo, se cierra solo al salir del LOOP. Es un gusto personal pero me parece mucho mas facil asi.

Por cierto no te olvides del COMMIT!!!
Jaja nono, commit puesto, y gracias, probaré el recordset.
Prueba como te dice Txukie:

------ Procedimiento para generar recibos de cada alumno matriculados end cada servicio
CREATE OR REPLACE PROCEDURE Pr_Genera_Recibos
IS
v_Alumno_id Recibos_vigentes.ALUMNO_ID%TYPE;
v_Alumno_nom Recibos_vigentes.ALUMNO_NOM%TYPE;
v_Alumno_ape Recibos_vigentes.ALUMNO_APE%TYPE;
v_Tutor_id Recibos_vigentes.TUTOR_ID%TYPE;
v_Tutor_nom Recibos_vigentes.TUTOR_NOM%TYPE;
v_Tutor_ape Recibos_vigentes.TUTOR_APE%TYPE;
v_Serv_id Recibos_vigentes.SERV_ID%TYPE;
v_Serv_nom Recibos_vigentes.SERV_NOM%TYPE;
v_Serv_Coste Recibos_vigentes.SERV_COSTE%TYPE;
v_Nro_banco Recibos_vigentes.NRO_BANCO%TYPE;
v_Nro_cuenta Recibos_vigentes.NRO_CUENTA%TYPE;

-- Cursor que selecciona los datos del recibo de todos los campos necesarios para la tabla de recibo. Con los INNER JOIN nos aseguramos de que solo recoja una ocurrencia para cada registro de la tabla Alumno_Servicio_Cuenta
CURSOR c_Matriculas IS
SELECT a.Alumno_id, a.nombre, a.Apellidos, t.Tutor_id, t.Nombre, t.apellidos, s.Servicio_id, s.Nombre, s.Precio_mes, a_s_c.Nro_banco, a_s_c.Nro_cuenta
FROM Alumno_Servicio_Cuenta a_s_c INNER JOIN Alumno a ON a_s_c.Alumno_id = a.Alumno_id INNER JOIN Tutor t ON a.Tutor_id = t.Tutor_id INNER JOIN Servicio s ON a_s_c.Servicio_id = s.Servicio_id;

BEGIN
DBMS_OUTPUT.PUT_LINE("Generando recibos...");
DBMS_OUTPUT.PUT_LINE("");

--OPEN c_Matriculas;
--FETCH c_Matriculas INTO v_Alumno_id, v_Alumno_nom, v_Alumno_ape, v_Tutor_id, v_Tutor_nom, v_Tutor_ape, v_Serv_id, v_Serv_nom, v_Serv_Coste, v_Nro_banco, v_Nro_cuenta;

FOR i IN c_Matriculas LOOP

INSERT INTO Recibos_vigentes(Recibo_id,
Alumno_id,
Alumno_nom,
Alumno_ape,
Tutor_id,
Tutor_nom,
Tutor_ape,
Serv_id,
Serv_nom,
Serv_Coste,
Nro_banco,
Nro_cuenta)
VALUES(Id_Recibo.NEXTVAL,
i.Alumno_id,
i.Alumno_nom,
i.Alumno_ape,
i.Tutor_id,
i.Tutor_nom,
i.Tutor_ape,
i.Serv_id,
i.Serv_nom,
i.Serv_Coste,
i.Nro_banco,
i.Nro_cuenta);

END LOOP;


--FETCH c_Matriculas INTO v_Alumno_id, v_Alumno_nom, v_Alumno_ape, v_Tutor_id, v_Tutor_nom, v_Tutor_ape, v_Serv_id, v_Serv_nom, v_Serv_Coste, v_Nro_banco, v_Nro_cuenta;

--EXIT WHEN c_Matriculas%NOTFOUND;
--END LOOP;

--CLOSE c_Matriculas;
DBMS_OUTPUT.PUT_LINE("Recibos generados");

END;
/


Salu2.
Odio las variables i, j, x y y z.


Espero por tu bien que cuando programes uses otros nombres [mad]






:-P
Gracias por preocuparte por la salud de mi programación, pero es lo más normal usar variables como i o j en un LOOP otra cosa es que la usaras en salario por ej. donde lo correcto sería usar algo como v_salario.

Sal2.
9 respuestas