Problemas con cursores dentro del procedimiento

Quisiera que por favor nos ayudara con un procedimiento que realice pero no me funciona.
Resulta que tengo un cursor dentro del procedimiento, el procedimiento debe tomar valores de 2 tablas y llenar una tercera tabla con esos valores, ademas debe realizar unas sumatorias de las tablas anteriores, para actualizar la tercera tabla, resulta que si la tercera tabla tiene datos el procedimiento debe actualizarlos, pero sino debe insertar datos, el error que me sale al ejecutar el procedimiento es
LINE/COL ERROR
-------- ----------------------------------------------------------------
27/1 PL/SQL: SQL Statement ignored
27/19 PLS-00403: la expresión 'R_UNO' no se puede utilizar como un
destino INTO de una sentencia SELECT/FETCH
29/1 PL/SQL: SQL Statement ignored
33/43 PLS-00330: uso incorrecto del nombre del tipo o del nombre del
subtipo
33/43 PL/SQL: ORA-00904: nombre de columna no válido
35/6 PL/SQL: SQL Statement ignored
40/14 PLS-00302: el componente 'VL_EXPRE' se debe declarar
40/14 PL/SQL: ORA-00984: columna no permitida aquí
El problema es que VL_EXPRE si esta declarada, por lo demás no entiendo de porque el error aquí le mando el procedimiento dentro del package para que por favor me pueda ayudar
CREATE OR REPLACE PACKAGE pk_totxabona AS
TYPE r_uno IS RECORD(
CONT_SAT NUMBER(6),
COD_CUENTA NUMBER(10),
ABONADOA VARCHAR2(15),
ANNO NUMBER(4),
MES NUMBER(2),
DESTINO VARCHAR2(15),
CLASE VARCHAR2(15),
NOVEDAD CHAR(1),
VLR_LLAM NUMBER(12,2),
VLR_MIN NUMBER(12,2),
VLR_DESC NUMBER(12,2),
VLR_EXPRESO NUMBER(12,2)
);
TYPE c_uno IS REF CURSOR ;
PROCEDURE pr_totxabonado(
salida out c_uno);
END;
/
CREATE OR REPLACE PACKAGE BODY pk_totxabona AS
PROCEDURE pr_totxabonado(
salida out c_uno)
IS
BEGIN
OPEN salida FOR
SELECT DISTINCT
A.CONT_SAT,
A.COD_CUENTA,
a.abonadoa,
B.ANNO,
B.MES,
b.destino,
B.CLASE,
b.novedad,
SUM(B.VLR_LLAM),
SUM(B.VLR_MIN),
SUM(B.VLR_LLAM)-SUM(B.VLR_EXPRESO),
SUM(B.VLR_EXPRESO)
FROM TELCUENT A, DETLD B
WHERE A.ABONADOA = '76322472'
AND A.ABONADOA = B.ABONADOA
GROUP BY A.CONT_SAT, A.COD_CUENTA, A.ABONADOA, B.ANNO,
B.MES, B.DESTINO, B.CLASE, B.NOVEDAD;
FETCH salida INTO r_uno;
IF SQL%FOUND THEN
UPDATE TOTXABONADO
SET VLR_ABONADO = VLR_ABONADO + R_UNO.VLR_LLAM,
MIN_ABONADO = MIN_ABONADO + R_UNO.VLR_MIN,
DESC_ABONADO = DESC_ABONADO + R_UNO.VLR_DESC,
EXPR_ABONADO = EXPR_ABONADO + R_UNO.VLR_EXPRESO;
ELSE IF SQL%NOTFOUND THEN
INSERT INTO TOTXABONADO
VALUES (R_UNO.VL_CONSAT,R_UNO.VL_CODCTA,R_UNO.VL_YEAR,
R_UNO.VL_MES,R_UNO.VL_ABONA,R_UNO.VL_DEST, R_UNO.VL_CLASE,
R_UNO.VL_NOVEDAD,R_UNO.VL_ABON, R_UNO.VL_MNABON,
R_UNO.VL_DESC,
R_UNO.VL_EXPRE);
END IF;
END IF;
COMMIT;
END;
END;
/

1 Respuesta

Respuesta
1
En primer lugar, decirte que existen varias formas de tratar los cursores. La forma que tu propones se utiliza más bien cuando tienes que abrir y cerrar varios cursores y no está definido cuáles se van a utilizar cada vez (de forma que puedes decidir si abres unos u otros).
Para el Problema que me cuentas, no es necesario que emplees este método, ya que hay otro mucho más sencillo y más eficiente.
Bueno, la verdad es que no he podido adivinar cómo son las tablas que utilizas, ni cómo es la carga de forma precisa, así que me he inventado un ejemplo que creo que es bastante similar.
Supongamos tres tablas:
a) Va a contener los datos de una serie de coches.
Coches
--------------------------------------------------------------
COD_COCHE NUMBER(6)
Modelo varchar2(15)
Donde COD_COCHE es el código del coche y MODELO es una descripción del modelo de coche.
b) En ella se van a guardar los datos de todos los viajes de cada coche.
Viajes
--------------------------------------------------------------
COD_VIAJE NUMBER(6)
COD_COCHE NUMBER(6)
NUM_KM NUMBER(4)
Tiempo number(4)
Donde COD_VIAJE es el código del viaje, COD_COCHE es el código del coche que ha realizado el viaje, NUM_KM la distancia recorrida en km y TIEMPO el tiempo empleado en horas.
c) Se generará un resumen de todos los viajes de cada coche, totalizando el número de km recorridos y sacando la velocidad media.
Resumen
--------------------------------------------------------------
COD_COCHE NUMBER(6)
MODELO VARCHAR2(15)
NUM_KM_TOTALES NUMBER(10)
TIEMPO_TOTAL NUMBER(10)
VELOCIDAD_MEDIA NUMBER(3)
Donde COD_COCHE es el código de coche, MODELO es la descripción del modelo de coche, NUM_KM_TOTALES es la suma de las distancias de cada viaje de dicho coche en km, y VELOCIDAD_MEDIA es el ratio entre el múmero de kilómetros total y el tiempo total empleado.
De esta forma, cada coche puede tener dos situaciones:
1.- Que no haya realizado viajes, con lo que hay que insertar en la tabla RESUMEN los datos del coche y dejar nulos TIEMPO_TOTAL y VELOCIDAD_MEDIA.
2.- Que ya haya realizado viajes, con lo que habría que actualizar los datos en la tabla RESUMEN.
La forma más sencilla de hacerlo sería la siguiente:
Create or replace package pak_siger is
PROCEDURE pr_resumir ();
END;
/
create or replace package body pak_siger is
PROCEDURE pr_resumir () is
//Definimos variables de traspaso
v_cod_coche NUMBER(6); //Recoge codigos de coche
v_modelo VARCHAR2(15); //Recoge modelos
v_num_km_totales NUMBER(10); //Recoge la suma total de km de un coche
v_tiempo_total NUMBER(10); //Recoge el tiempo total empleado por un coche
v_velocidad_meia NUMBER(3); //Recoge el valor de la velocidad media
//Definimos un cursor que recorra la tabla COCHES
cursor C1 is(
select COD_COCHE, MODELO
from COCHES);
//Definimos una variable de tipo "registro del cursos c1"
R1 C1%rowtype;
BEGIN
//Inicializamos las variables numericas
v_num_km_totales := NULL;
v_tiempo_total := NULL;
v_velocidad_media := NULL;
for R1 in C1 //Recorremos el cursor (todos los coches que tenemos registrados)
loop
//Recogemos algunos valores en las variables
v_cod_coche := R1.COD_COCHE;
v_modelo := R1.MODELO;
//Recogemos el resto de valores en las variables
BEGIN
select sum(NUM_KM), sum(TIEMPO), sum(NUM_KM)/sum(TIEMPO)
into v_num_km_totales, v_tiempo_total, v_velocidad_media
from VIAJES
where COD_COCHE = v_cod_coche;
EXCEPTION
when no_data_found then //Si no encuentra datos en la tabla VIAJES (no hay viajes)
//Tenemos que registrar el coche (codigo y modelo)
insert into RESUMEN
values(v_cod_coche, v_modelo, NULL, NULL, NULL);
END;
if V_NUM_KM_TOTALES is not null then //Si existen viajes, hay que actualizar
update RESUMEN
set NUM_KM_TOTALES = v_num_km_totales,
TIEMPO_TOTAL = v_tiempo_total,
VELOCIDAD_MEDIA = v_velocidad_media
where COD_COCHE = v_cod_coche
and MODELO = v_modelo;
end if;
end loop;
END;
/
Espero que no te sea muy difícil ajustar este ejemplo a tu problema en concreto. Si no lo ves claro, mándame cómo están definidas las tablas y cómo es la carga de datos.
Suerte.
Muchas gracias por la solución que me has enviado de verdad que es muy similar al que estoy desarrollando, voy a adaptarlo al verdadero y luego te escribo para contarte como me resulto.
Mil gracias

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas