Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » Mysql »

Procedimiento Almacenado

Estas en el tema de Procedimiento Almacenado en el foro de Mysql en Foros del Web. Buenos Dias Tengo este procedimiento almacenado me realiza un proceso de mayoriazacion dependiendo del centro de costo, cuando realizo una consulta en la que me ...
  #1 (permalink)  
Antiguo 26/06/2015, 07:15
Avatar de JeMaGa  
Fecha de Ingreso: julio-2011
Ubicación: Bogota
Mensajes: 430
Antigüedad: 12 años, 9 meses
Puntos: 4
Procedimiento Almacenado

Buenos Dias
Tengo este procedimiento almacenado me realiza un proceso de mayoriazacion dependiendo del centro de costo, cuando realizo una consulta en la que me muestra el valor mayor no me funciona la insercion pero si quieto esta consulta si funciona, pero no como deberia

Agradeceria toda la ayuda que me puedan brindar
Código MySQL:
Ver original
  1. DROP PROCEDURE IF EXISTS ".$nombreProc.";
  2. CREATE DEFINER=`root`@`localhost` PROCEDURE `".$nombreProc."`() DETERMINISTIC NO SQL SQL SECURITY DEFINER
  3. DECLARE v_tercero VARCHAR (20);
  4. DECLARE v_id_cabecera INT DEFAULT 0;
  5. DECLARE v_id_saldo INT DEFAULT 0;
  6. DECLARE v_codigo_cuenta VARCHAR(20);
  7. DECLARE v_sucursal VARCHAR(4);
  8. DECLARE v_debito DOUBLE(15,2);
  9. DECLARE v_credito DOUBLE(15,2);
  10. DECLARE v_centro_costo VARCHAR(6);
  11. DECLARE v_centro_costo_ce VARCHAR(6);
  12. DECLARE padre_centro_costo VARCHAR(6);
  13. DECLARE numero_paso INT DEFAULT 0;
  14. DECLARE tmp_continuar INT DEFAULT 0;
  15. DECLARE detalle_cur CURSOR FOR SELECT detalle.id_cabecera, detalle.codigo_cuenta, detalle.sucursal, detalle.debito, detalle.credito, detalle.tercero, detalle.centrocosto FROM " . $tablaMes . " as detalle HAVING detalle.id_cabecera = " . $idComprobante . ";
  16. DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET continuar = false;
  17. OPEN detalle_cur;
  18.     FETCH  detalle_cur INTO v_id_cabecera, v_codigo_cuenta, v_sucursal, v_debito, v_credito, v_tercero, v_centro_costo;
  19.     SET tmp_continuar = continuar;
  20.     SELECT v_codigo_cuenta, v_sucursal, v_debito, v_credito, v_tercero, v_centro_costo;
  21.    
  22.     IF v_codigo_cuenta IS NOT NULL THEN
  23.         loop_interno: LOOP
  24.        
  25.            SELECT id_centro_costo,id_padre FROM centros_costo WHERE id_centro_costo = v_centro_costo
  26.            INTO v_centro_costo_ce, padre_centro_costo;
  27.            SELECT v_centro_costo_ce, padre_centro_costo;
  28.  
  29.                     SET v_id_saldo=0;
  30.                     SELECT id FROM " . $tablaSaldos . " WHERE cuenta = v_codigo_cuenta and tercero = v_tercero and sucursal = v_sucursal and centroCosto = v_centro_costo INTO v_id_saldo;
  31.                     IF  v_id_saldo = 0 THEN
  32.                         INSERT INTO " . $tablaSaldos . " (cuenta,tercero,sucursal,centroCosto," . $campoDebito . "," . $campoCredito . ") VALUES(`v_codigo_cuenta`,`v_tercero`,`v_sucursal`, `v_centro_costo`,v_debito,v_credito);
  33.                     ELSE
  34.                         UPDATE " . $tablaSaldos . " SET " . $campoDebito . " = " . $campoDebito . $signo . " v_debito, " . $campoCredito . " = " . $campoCredito . $signo . " v_credito WHERE id = v_id_saldo;
  35.                     END IF;  
  36.  
  37.               SET v_id_saldo=0;
  38.               SELECT id FROM " . $tablaSaldos . " WHERE cuenta = v_codigo_cuenta and tercero IS NULL and sucursal IS NULL into v_id_saldo;
  39.               IF  v_id_saldo = 0 THEN
  40.                    INSERT INTO " . $tablaSaldos . " (cuenta,centroCosto," . $campoDebito . "," . $campoCredito . ") VALUES(`v_codigo_cuenta`,`v_centro_costo`,v_debito,v_credito);                        
  41.               ELSE
  42.                    UPDATE " . $tablaSaldos . " SET " . $campoDebito . " = " . $campoDebito . $signo . " v_debito, " . $campoCredito . " = " . $campoCredito . $signo . " v_credito WHERE id = v_id_saldo;
  43.               END IF;
  44.                
  45.            SET v_centro_costo = padre_centro_costo;
  46.            IF  v_centro_costo IS NULL THEN
  47.               LEAVE loop_interno;  
  48.            END IF;
  49.         END LOOP loop_interno;
  50.     END IF;
  51.     SET continuar= tmp_continuar;
  52. UNTIL NOT continuar END REPEAT;
  53. CLOSE detalle_cur;    
[/PHP]

Última edición por gnzsoloyo; 26/06/2015 a las 14:32 Razón: Pesimamente etiquetado... SQL no es PHP.
  #2 (permalink)  
Antiguo 26/06/2015, 07:25
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Procedimiento Almacenado

Esto es OFF TOPIC en este foro.

No es PHP.

Es tema para el foro de MySQL.

Por otra parte, ¿eres consciente de que es una pésima práctica crear SP dinamicamente como lo estás haciendo?

Los SP son parte de las estructuras fijas de una base, y no deben crearse al azar. El hecho de que estés poniendo dinamicamente el nombre del SP y de las tablas me habla de serios errores de diseño de la estructura de datos y de la lógica del sistema..
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #3 (permalink)  
Antiguo 26/06/2015, 13:33
Avatar de Libras
Colaborador
 
Fecha de Ingreso: agosto-2006
Ubicación: En la hermosa perla de occidente
Mensajes: 7.412
Antigüedad: 17 años, 8 meses
Puntos: 774
Respuesta: Procedimiento Almacenado

un procedure que se elimina y se vuelve a crear?? Hacer eso le quita la funcionalidad al procedure porque el codigo de dentro del procedure se tiene que volver a cargar en cache para genera el plan de ejecucion cada vez que se cambie el nombre del procedure......
__________________
What does an execution plan say to t-sql query? Go f**k yourself, if you are not happy with me
  #4 (permalink)  
Antiguo 26/06/2015, 14:40
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Procedimiento Almacenado

Hay varias cosas a considerar:
1) Un SP es una tarea programada que puede estar compuesta de un único paso o múltiples pasos que se ejecutan en forma atómica. Pero es una tarea que se ejecuta siempre sobre los mismos objetos de la base (tablas y columnas).
2) No se construyen N procedimientos iguales con diferencia de nombres de tablas. Eso muestra que existen tablas con el mismo dominio que se usan para objetos de diferente clase. Eso implica que hay un ERROR DE DISEÑO en la base de datos.
3) Los CURSORes sólo se deben usar si es estrictamente necesario, y únicamente si devolverá N registros a recorrer, y si además se deben hacer tareas diferentes sobre ellos. Crear un cursor para tomar los datos e insertarlos en otra tabla, sin un procesamiento de los datos no tiene sentido. Se puede hacer lo mismo de otros modos mucho más eficientes.

Empieza por explicar en una forma sintética qué se supone que hace ese SP, y por qué crees que necesitas un cursor.
También sería bueno que expliques por qué tienes N tablas con la misma estructura de columnas. Por eso no tiene ningún sentido.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #5 (permalink)  
Antiguo 29/06/2015, 09:10
Avatar de JeMaGa  
Fecha de Ingreso: julio-2011
Ubicación: Bogota
Mensajes: 430
Antigüedad: 12 años, 9 meses
Puntos: 4
Respuesta: Procedimiento Almacenado

EL PROCEDIMIENTO QUE TENGO HASTA AHORA ES ASI

Código MySQL:
Ver original
  1. DROP PROCEDURE IF EXISTS " . $nombreProc . ";
  2. CREATE DEFINER=`root`@`localhost` PROCEDURE `" . $nombreProc . "`() DETERMINISTIC NO SQL SQL SECURITY DEFINER
  3. DECLARE v_tercero VARCHAR (20);
  4. DECLARE puc_cuenta VARCHAR(20);
  5. DECLARE puc_terceros INT DEFAULT 0;
  6. DECLARE puc_movimiento INT DEFAULT 0;
  7. DECLARE puc_mayor VARCHAR(20);
  8. DECLARE puc_centro_costo INT DEFAULT 0;
  9. DECLARE v_id_cabecera INT DEFAULT 0;
  10. DECLARE v_id_saldo INT DEFAULT 0;
  11. DECLARE v_codigo_cuenta VARCHAR(20);
  12. DECLARE v_sucursal VARCHAR(4);
  13. DECLARE v_debito DOUBLE(15,2);
  14. DECLARE v_credito DOUBLE(15,2);
  15. DECLARE v_centro_costo VARCHAR(6);
  16. DECLARE padre_centro_costo VARCHAR(6);
  17. DECLARE tmp_continuar INT DEFAULT 0;
  18. DECLARE detalle_cur CURSOR FOR SELECT detalle.id_cabecera, detalle.codigo_cuenta, detalle.sucursal, detalle.debito, detalle.credito, detalle.tercero, detalle.centrocosto FROM " . $tablaMes . " as detalle HAVING detalle.id_cabecera = " . $idComprobante . ";
  19. DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET continuar = false;
  20. OPEN detalle_cur;
  21.     FETCH  detalle_cur INTO v_id_cabecera, v_codigo_cuenta, v_sucursal, v_debito, v_credito, v_tercero, v_centro_costo;
  22.     SET tmp_continuar = continuar;
  23.     SELECT v_codigo_cuenta, v_sucursal, v_debito, v_credito, v_tercero, v_centro_costo;
  24.    
  25.     IF v_codigo_cuenta IS NOT NULL THEN
  26.         loop_interno: LOOP
  27.            SELECT codigo,movimiento,terceros,mayor,centrocosto FROM puc WHERE codigo = v_codigo_cuenta
  28.            INTO puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;
  29.            SELECT puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;
  30.               IF puc_movimiento=1 THEN
  31.                     IF puc_terceros=1 THEN
  32.                         SET v_id_saldo=0;
  33.                         SELECT id FROM ".$tablaSaldos." WHERE cuenta = v_codigo_cuenta and tercero = v_tercero and sucursal = v_sucursal INTO v_id_saldo;
  34.                         IF  v_id_saldo = 0 THEN
  35.                             INSERT INTO ".$tablaSaldos." (cuenta,tercero,sucursal,".$campoDebito.",".$campoCredito.") VALUES(`v_codigo_cuenta`,`v_tercero`,`v_sucursal`,v_debito,v_credito);
  36.                         ELSE
  37.                             UPDATE ".$tablaSaldos." SET ".$campoDebito." = ".$campoDebito.$signo." v_debito, ".$campoCredito." = ".$campoCredito.$signo." v_credito WHERE id = v_id_saldo;
  38.                         END IF;
  39.                     END IF;
  40.               END IF;
  41.                 IF puc_centro_costo = 1 THEN
  42.                     loop_centro: LOOP
  43.                        
  44.                        SELECT id_padre FROM centros_costo WHERE id_centro_costo = v_centro_costo INTO padre_centro_costo;
  45.                        SELECT padre_centro_costo;
  46.  
  47.                         SET v_id_saldo=0;
  48.                         SELECT id FROM ".$tablaSaldos." WHERE cuenta = v_codigo_cuenta and tercero = v_tercero and sucursal = v_sucursal INTO v_id_saldo;
  49.                         IF  v_id_saldo = 0 THEN
  50.                             INSERT INTO " . $tablaSaldos . " (cuenta,tercero,sucursal,centroCosto," . $campoDebito . "," . $campoCredito . ") VALUES(`v_codigo_cuenta`,`v_tercero`,`v_sucursal`, `v_centro_costo`,v_debito,v_credito);
  51.                         ELSE
  52.                             UPDATE " . $tablaSaldos . " SET " . $campoDebito . " = " . $campoDebito . $signo . " v_debito, " . $campoCredito . " = " . $campoCredito . $signo . " v_credito WHERE id = v_id_saldo;
  53.                         END IF;  
  54.                        
  55.                        SET v_centro_costo = padre_centro_costo;
  56.                        IF  v_centro_costo IS NULL THEN        
  57.                           LEAVE loop_centro;   
  58.                        END IF;
  59.                        
  60.                     END LOOP loop_centro;
  61.                 END IF;
  62.                            
  63.                 SET v_id_saldo=0;
  64.                 SELECT id FROM ".$tablaSaldos." WHERE cuenta = v_codigo_cuenta and tercero = v_tercero and sucursal = v_sucursal INTO v_id_saldo;
  65.                 IF  v_id_saldo = 0 THEN
  66.                     INSERT INTO " . $tablaSaldos . " (cuenta,tercero,sucursal,centroCosto," . $campoDebito . "," . $campoCredito . ") VALUES(`v_codigo_cuenta`,`v_tercero`,`v_sucursal`, `v_centro_costo`,v_debito,v_credito);
  67.                 ELSE
  68.                     UPDATE " . $tablaSaldos . " SET " . $campoDebito . " = " . $campoDebito . $signo . " v_debito, " . $campoCredito . " = " . $campoCredito . $signo . " v_credito WHERE id = v_id_saldo;
  69.                 END IF;
  70.            SET v_codigo_cuenta = puc_mayor;
  71.            IF  v_codigo_cuenta IS NULL THEN
  72.               LEAVE loop_interno;  
  73.            END IF;
  74.         END LOOP loop_interno;
  75.     END IF;
  76.     SET continuar= tmp_continuar;
  77. UNTIL NOT continuar END REPEAT;
  78. CLOSE detalle_cur;
  79. END";

El diseñadoor de la base de datos crea una tabla que se encarga de guardar la mayorización de proceso contable por año, por eso lo del procedimiento que crea tablas diferentes nombres estructura igual.
La idea del procedimiento es que si yo ingreso una cuenta con un centro de costo

11050502 con un centro de costo 102030
11100503 sin centro de costo

en mi base de datos en mi tabla me debe guardar el padre de la cuenta y del centro de costo, pero si mi cuenta no tiene centro de costo solo ingrese el padre de la cuenta con el centro de costo null

Lo que debe hacer...........

CUENTA CENTRO_COSTO

11100503 NULL
111005 NULL
1110 NULL
11 NULL
1 NULL
11050502 102030
11050502 102000
11050502 100000
11050502

110505 102030
110505 102000
110505 100000
110505

1105 102030
1105 102000
1105 100000
1105

11 102030
11 102000
11 100000
11

1 102030
1 102000
1 100000
1

eso es lo que me debe hacer el procedimiento, pero el procedimiento que hasta el momento tengo solo me guarda

Lo que hace .............

CUENTA CENTRO COSTO

11100503 NULL
111005 NULL
1110 NULL
11 NULL
1 NULL
11050502 102030
11050502 102000
11050502 100000
11050502

nose por donde mas moverle, llevo 4 dias en lo mismo y no he podido encontrar la solución agradezco toda la ayuda que me puedan brindar

Última edición por gnzsoloyo; 29/06/2015 a las 11:41
  #6 (permalink)  
Antiguo 29/06/2015, 10:05
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Procedimiento Almacenado

OK...
En primer lugar, no necesitas crear una tabla por año para la tarea que describes. Lo mejor sería realizar un particionamiento de la tabla por años, como en cualquier otro DBMS. De ese modo la tabla sería siempre la misma pero se accedería a la información de cada año en función de los parametros de fecha.
Eso evitaría andar creando y destruyendo SM de forma dinámica, cosa que es una pésima práctica.
¿Eso se entiende?
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #7 (permalink)  
Antiguo 29/06/2015, 11:18
Avatar de JeMaGa  
Fecha de Ingreso: julio-2011
Ubicación: Bogota
Mensajes: 430
Antigüedad: 12 años, 9 meses
Puntos: 4
Respuesta: Procedimiento Almacenado

Ok, gracias por tus recomendaciones pero como te dije, el administrador y diseñador de la base de datos lo puso asi, yo no puedo cambiar el diseño y el planteamiento de la base de datos, yo soy el desarrollador, entiendo que es un mal habito y nada practico, pero asi esta.

No se si de alguna forma se puede trabajar en el procedimiento, tal cual como esta la tabla con la creación dinamica

Gracias!
  #8 (permalink)  
Antiguo 29/06/2015, 11:44
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Procedimiento Almacenado

Ok.
Empecemos por el principio: Ese script lo que hace es crear un SP con un nombre que entra por parámetro, y con un body (cuerpo de código SQL) que contiene a partir de ese momento el nombre de una tabla. AL ser creado, tanto el nombre del SP como el de la tabla contenida en el SP pasan a ser nombres fijos.
Esto implica que deberás ejecutar esa creación de SP tantas veces como tablas iguales y con diferente nombre tengas, pero sólo una vez por cada ocasión.
Eso lo tienes claro, supongo, ¿no?

No se debe, bajo ninguna circunstancia, andar recreando SP en cada ejecución, es decir no destruyes un SP para crear otro cada vez que quieres cambiar de tabla a leer..

A partir de la creación, entonces, simplemente invocas al SP de acuerdo a la necesidad de la tabla que usarás. En ese contexto es donde realmente aparece este problema:
Cita:
eso es lo que me debe hacer el procedimiento, pero el procedimiento que hasta el momento tengo solo me guarda

Lo que hace .............

CUENTA CENTRO COSTO

11100503 NULL
111005 NULL
1110 NULL
11 NULL
1 NULL
11050502 102030
11050502 102000
11050502 100000
11050502
En esencia, como el comportamiento variará de acuedo a la tabla que se consulte en el momento de ejecución, y puede que dos ejecuciones no tengan la misma tabla, habría que debuggear un caso puntual, donde la tabla que se invoque sea la misma, para saber si esto realmente está ocurriendo, o es que dos ejecuciones invocan a tablas diferentes.

Eso por un lado.

Por otro, a simple vista veo algunas cosas que pueden causar problemas:
Código MySQL:
Ver original
  1. SELECT codigo, movimiento, terceros,mayor, centrocosto
  2. FROM puc WHERE codigo = v_codigo_cuenta
  3. INTO puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;
  4. SELECT puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;
Ese segundo select genera una salida al buffer de consultas que no debería existir hasta el final del SP. Una de las consecuencias posibles es que se interrumpa la ejecución de tu script programado antes que la ejecución del SP termine, y la aplicación no se entera, porque ya leyó un resultado... y tu lo haces al menos en tres partes diferentes.

A la noche lo revisaré mejor, pero me da la impresión de que la lógica contenida no está correctamente armada.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #9 (permalink)  
Antiguo 29/06/2015, 12:57
Avatar de JeMaGa  
Fecha de Ingreso: julio-2011
Ubicación: Bogota
Mensajes: 430
Antigüedad: 12 años, 9 meses
Puntos: 4
Respuesta: Procedimiento Almacenado

el procedimiento solo se ejecuta en una unica tabla, llamada saldos_contables_[año actual] la estructura de esta tabla es

id int(10)
cuenta varchar(20)
sucursal varchar(4)
tercero varchar(20)
centroCosto varchar(6)
db_06 double(15,2)
cr_06 double(15,2)

siempre va ser la misma, lo que varia son los codigos de cuenta y los centros de costo
Código MySQL:
Ver original
  1. SELECT codigo, movimiento, terceros,mayor, centrocosto ROM puc WHERE codigo =v_codigo_cuenta  INTO puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;
  2. SELECT puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;

esta consulta lo unico que hace es consultarme el codigo contable mayor al que esta en ese momento cargada es decir esa consulta me muestra el mayor de 11050502, y solo se ejecuta en una parte que es al principio.

El problema que yo se que es y que veo es que en el procedimiento tengo 2 loop
uno para el codigo_contable (loop_interno) muestra el mayor

11050502
110505
1105 ..

pero dentro de ese loo_interno hay otro que se encargar de mostrar el padre del centro de costo (loop_centro)

102030
102000
100000

el problema es que cuando llega a ejecutar el loop_centro funciona la primera vez

Código MySQL:
Ver original
  1. loop_centro: LOOP      
  2.   SET v_id_saldo=0;
  3.   SELECT id FROM ".$tablaSaldos." WHERE cuenta = v_codigo_cuenta and tercero = v_tercero and centroCosto = v_centro_costo INTO v_id_saldo; //en este momento me trae el codigo 11050502 y el centro_costo =102030
  4.   IF  v_id_saldo = 0 THEN
  5.      INSERT INTO " . $tablaSaldos . " (cuenta,tercero,sucursal,centroCosto," . $campoDebito . "," . $campoCredito . ") VALUES(`v_codigo_cuenta`,`v_tercero`,`v_sucursal`, `v_centro_costo`, v_debito, v_credito); // inserta en la tabla saldos_contables_2015 ese registro 11050502 102030
  6.   ELSE
  7.      UPDATE " . $tablaSaldos . " SET " . $campoDebito . " = " . $campoDebito . $signo . " v_debito, " . $campoCredito . " = " . $campoCredito . $signo . " v_credito WHERE id = v_id_saldo;
  8.   END IF;  
  9.  
  10.   SELECT id_padre FROM centros_costo WHERE id_centro_costo = v_centro_costo INTO padre_centro_costo; // consulta el padre del centro de costo 102030
  11.   SELECT padre_centro_costo;
  12.  
  13.    SET v_centro_costo = padre_centro_costo; //aqui le esta a la variable v_centro_costo asignando 102000
  14.    IF  v_centro_costo IS NULL THEN    // como el valor de  v_centro_costo no es NULL  no se me sale del loop y lo sigue ejecutando
  15.       LEAVE loop_centro;   
  16.    END IF;                
  17. END LOOP loop_centro;

como en el ultimo centro de costo es 100000 y el padre es NULL ahi cierra el loop_centro y lo saca y ahi detiene todo el proceso algo que no deberia hacer, por que cuando me salga de ese loop_centro deberia seguir ejecutando el loop_interno para que me siga ejecutando la cuenta

o por lo menos eso es lo que deberia estar haciendo. que cuando termina de ejecutar loop_centro debe continuar la ejecucion de loop_interno hasta que este tambien se cierre

Última edición por gnzsoloyo; 30/06/2015 a las 06:09 Razón: MUY MAL ETIQUETADO
  #10 (permalink)  
Antiguo 29/06/2015, 14:21
Avatar de JeMaGa  
Fecha de Ingreso: julio-2011
Ubicación: Bogota
Mensajes: 430
Antigüedad: 12 años, 9 meses
Puntos: 4
procedimiento almacenado con loop

EL PROCEDIMIENTO QUE TENGO HASTA AHORA ES ASI

Código MySQL:
Ver original
  1. DROP PROCEDURE IF EXISTS " . $nombreProc . ";
  2. CREATE DEFINER=`root`@`localhost` PROCEDURE `" . $nombreProc . "`() DETERMINISTIC NO SQL SQL SECURITY DEFINER
  3. DECLARE v_tercero VARCHAR (20);
  4. DECLARE puc_cuenta VARCHAR(20);
  5. DECLARE puc_terceros INT DEFAULT 0;
  6. DECLARE puc_movimiento INT DEFAULT 0;
  7. DECLARE puc_mayor VARCHAR(20);
  8. DECLARE puc_centro_costo INT DEFAULT 0;
  9. DECLARE v_id_cabecera INT DEFAULT 0;
  10. DECLARE v_id_saldo INT DEFAULT 0;
  11. DECLARE v_codigo_cuenta VARCHAR(20);
  12. DECLARE v_sucursal VARCHAR(4);
  13. DECLARE v_debito DOUBLE(15,2);
  14. DECLARE v_credito DOUBLE(15,2);
  15. DECLARE v_centro_costo VARCHAR(6);
  16. DECLARE padre_centro_costo VARCHAR(6);
  17. DECLARE tmp_continuar INT DEFAULT 0;
  18. DECLARE detalle_cur CURSOR FOR SELECT detalle.id_cabecera, detalle.codigo_cuenta, detalle.sucursal, detalle.debito, detalle.credito, detalle.tercero, detalle.centrocosto FROM " . $tablaMes . " as detalle HAVING detalle.id_cabecera = " . $idComprobante . ";
  19. DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET continuar = false;
  20. OPEN detalle_cur;
  21.     FETCH  detalle_cur INTO v_id_cabecera, v_codigo_cuenta, v_sucursal, v_debito, v_credito, v_tercero, v_centro_costo;
  22.     SET tmp_continuar = continuar;
  23.     SELECT v_codigo_cuenta, v_sucursal, v_debito, v_credito, v_tercero, v_centro_costo;
  24.    
  25.     IF v_codigo_cuenta IS NOT NULL THEN
  26.         loop_interno: LOOP
  27.            SELECT codigo,movimiento,terceros,mayor,centrocosto FROM puc WHERE codigo = v_codigo_cuenta
  28.            INTO puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;
  29.            SELECT puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;
  30.               IF puc_movimiento=1 THEN
  31.                     IF puc_terceros=1 THEN
  32.                         SET v_id_saldo=0;
  33.                         SELECT id FROM ".$tablaSaldos." WHERE cuenta = v_codigo_cuenta and tercero = v_tercero and sucursal = v_sucursal INTO v_id_saldo;
  34.                         IF  v_id_saldo = 0 THEN
  35.                             INSERT INTO ".$tablaSaldos." (cuenta,tercero,sucursal,".$campoDebito.",".$campoCredito.") VALUES(`v_codigo_cuenta`,`v_tercero`,`v_sucursal`,v_debito,v_credito);
  36.                         ELSE
  37.                             UPDATE ".$tablaSaldos." SET ".$campoDebito." = ".$campoDebito.$signo." v_debito, ".$campoCredito." = ".$campoCredito.$signo." v_credito WHERE id = v_id_saldo;
  38.                         END IF;
  39.                     END IF;
  40.               END IF;
  41.                 IF puc_centro_costo = 1 THEN
  42.                     loop_centro: LOOP
  43.                        
  44.                        SELECT id_padre FROM centros_costo WHERE id_centro_costo = v_centro_costo INTO padre_centro_costo;
  45.                        SELECT padre_centro_costo;
  46.  
  47.                         SET v_id_saldo=0;
  48.                         SELECT id FROM ".$tablaSaldos." WHERE cuenta = v_codigo_cuenta and tercero = v_tercero and sucursal = v_sucursal INTO v_id_saldo;
  49.                         IF  v_id_saldo = 0 THEN
  50.                             INSERT INTO " . $tablaSaldos . " (cuenta,tercero,sucursal,centroCosto," . $campoDebito . "," . $campoCredito . ") VALUES(`v_codigo_cuenta`,`v_tercero`,`v_sucursal`, `v_centro_costo`,v_debito,v_credito);
  51.                         ELSE
  52.                             UPDATE " . $tablaSaldos . " SET " . $campoDebito . " = " . $campoDebito . $signo . " v_debito, " . $campoCredito . " = " . $campoCredito . $signo . " v_credito WHERE id = v_id_saldo;
  53.                         END IF;  
  54.                        
  55.                        SET v_centro_costo = padre_centro_costo;
  56.                        IF  v_centro_costo IS NULL THEN        
  57.                           LEAVE loop_centro;    
  58.                        END IF;
  59.                        
  60.                     END LOOP loop_centro;
  61.                 END IF;
  62.                            
  63.                 SET v_id_saldo=0;
  64.                 SELECT id FROM ".$tablaSaldos." WHERE cuenta = v_codigo_cuenta and tercero = v_tercero and sucursal = v_sucursal INTO v_id_saldo;
  65.                 IF  v_id_saldo = 0 THEN
  66.                     INSERT INTO " . $tablaSaldos . " (cuenta,tercero,sucursal,centroCosto," . $campoDebito . "," . $campoCredito . ") VALUES(`v_codigo_cuenta`,`v_tercero`,`v_sucursal`, `v_centro_costo`,v_debito,v_credito);
  67.                 ELSE
  68.                     UPDATE " . $tablaSaldos . " SET " . $campoDebito . " = " . $campoDebito . $signo . " v_debito, " . $campoCredito . " = " . $campoCredito . $signo . " v_credito WHERE id = v_id_saldo;
  69.                 END IF;
  70.            SET v_codigo_cuenta = puc_mayor;
  71.            IF  v_codigo_cuenta IS NULL THEN
  72.               LEAVE loop_interno;  
  73.            END IF;
  74.         END LOOP loop_interno;
  75.     END IF;
  76.     SET continuar= tmp_continuar;
  77. UNTIL NOT continuar END REPEAT;
  78. CLOSE detalle_cur;

El diseñador de la base de datos crea una tabla que se encarga de guardar la mayorización de proceso contable por año, por eso lo del procedimiento que crea tablas diferentes nombres estructura igual.
La idea del procedimiento es que si yo ingreso una cuenta con un centro de costo

11050502 con un centro de costo 102030
11100503 sin centro de costo

en mi base de datos en mi tabla me debe guardar el padre de la cuenta y del centro de costo, pero si mi cuenta no tiene centro de costo solo ingrese el padre de la cuenta con el centro de costo null

Lo que debe hacer...........

CUENTA CENTRO_COSTO

11100503 NULL
111005 NULL
1110 NULL
11 NULL
1 NULL
11050502 102030
11050502 102000
11050502 100000
11050502

110505 102030
110505 102000
110505 100000
110505

1105 102030
1105 102000
1105 100000
1105

11 102030
11 102000
11 100000
11

1 102030
1 102000
1 100000
1

eso es lo que me debe hacer el procedimiento, pero el procedimiento que hasta el momento tengo solo me guarda

Lo que hace .............

CUENTA CENTRO COSTO

11100503 NULL
111005 NULL
1110 NULL
11 NULL
1 NULL
11050502 102030
11050502 102000
11050502 100000
11050502

el procedimiento solo se ejecuta en una unica tabla, llamada saldos_contables_[año actual] la estructura de esta tabla es

id int(10)
cuenta varchar(20)
sucursal varchar(4)
tercero varchar(20)
centroCosto varchar(6)
db_06 double(15,2)
cr_06 double(15,2)

siempre va ser la misma, lo que varia son los codigos de cuenta y los centros de costo

SELECT codigo, movimiento, terceros,mayor, centrocosto ROM puc WHERE codigo =v_codigo_cuenta INTO puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;
SELECT puc_cuenta, puc_movimiento, puc_terceros, puc_mayor, puc_centro_costo;

esta consulta lo unico que hace es consultarme el codigo contable mayor al que esta en ese momento cargada es decir esa consulta me muestra el mayor de 11050502, y solo se ejecuta en una parte que es al principio.

El problema que yo se que es y que veo es que en el procedimiento tengo 2 loop
uno para el codigo_contable (loop_interno) muestra el mayor

11050502
110505
1105 ..

pero dentro de ese loo_interno hay otro que se encargar de mostrar el padre del centro de costo (loop_centro)

102030
102000
100000

el problema es que cuando llega a ejecutar el loop_centro funciona la primera vez

Código MySQL:
Ver original
  1. loop_centro: LOOP        
  2.   SET v_id_saldo=0;
  3.   SELECT id FROM ".$tablaSaldos." WHERE cuenta = v_codigo_cuenta and tercero = v_tercero and centroCosto = v_centro_costo INTO v_id_saldo; //en este momento me trae el codigo 11050502 y el centro_costo =102030  
  4.   IF  v_id_saldo = 0 THEN
  5.      INSERT INTO " . $tablaSaldos . " (cuenta,tercero,sucursal,centroCosto," . $campoDebito . "," . $campoCredito . ") VALUES(`v_codigo_cuenta`,`v_tercero`,`v_sucursal`, `v_centro_costo`, v_debito, v_credito); // inserta en la tabla saldos_contables_2015 ese registro 11050502 102030
  6.   ELSE
  7.      UPDATE " . $tablaSaldos . " SET " . $campoDebito . " = " . $campoDebito . $signo . " v_debito, " . $campoCredito . " = " . $campoCredito . $signo . " v_credito WHERE id = v_id_saldo;
  8.   END IF;  
  9.  
  10.   SELECT id_padre FROM centros_costo WHERE id_centro_costo = v_centro_costo INTO padre_centro_costo; // consulta el padre del centro de costo 102030
  11.   SELECT padre_centro_costo;
  12.  
  13.    SET v_centro_costo = padre_centro_costo; //aqui le esta a la variable v_centro_costo asignando 102000
  14.    IF  v_centro_costo IS NULL THEN    // como el valor de  v_centro_costo no es NULL  no se me sale del loop y lo sigue ejecutando
  15.       LEAVE loop_centro;    
  16.    END IF;                
  17. END LOOP loop_centro;

como en el ultimo centro de costo es 100000 y el padre es NULL ahi cierra el loop_centro y lo saca y ahi detiene todo el proceso algo que no deberia hacer, por que cuando me salga de ese loop_centro deberia seguir ejecutando el loop_interno para que me siga ejecutando la cuenta

o por lo menos eso es lo que deberia estar haciendo. que cuando termina de ejecutar loop_centro debe continuar la ejecucion de loop_interno hasta que este tambien se cierre

Última edición por gnzsoloyo; 29/06/2015 a las 14:52
  #11 (permalink)  
Antiguo 30/06/2015, 07:04
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Procedimiento Almacenado

Mira, me puse a leer con cuidado el SP que posteas, y francamente le veo tantos problemas, y tanta falta de limpieza y claridad, que lo tendría que calificar, sin pretender ofenderte, de "código basura".
Creo que lo mejor sería que en lugar de intentar reparar esa cosa, empecemos desde cero, y tratemos de ver cual es el algoritmo que el SP debe cumplir, porque desde el vamos lo que no está clara es la secuencia descriptiva de pasos que deben ejecutarse y para qué.
Por otro lado, desde el inicio te recomiendo que desestimes el uso de cursores. No solo son ineficientes, sino que para el caso específico son INNECESARIOS, dado que iguales resultados se pueden obtener por métodos más performánticos.

¿Sabes escribir un detalle de Caso de Uso?
Cita:
1) El usuario inserta ....
2) El sistema recibe los datos ingresados y:
2.1. Realiza....
2.2. Calcula...
2.3. SI ... entonces .... sino, ....
Bueno, trata de escribir claramente los pasos y a partir de alli podemos crear un SP que realmente haga lo que necesitas.

Por otro lado te hago un comentario: OLVIDATE de ese SP. Está MAL hecho y usas los SP de un modo INCORRECTO.
No se necesita crear y destruir SP para, incluso, usar nombres de tablas variables.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #12 (permalink)  
Antiguo 30/06/2015, 07:59
Avatar de JeMaGa  
Fecha de Ingreso: julio-2011
Ubicación: Bogota
Mensajes: 430
Antigüedad: 12 años, 9 meses
Puntos: 4
Respuesta: Procedimiento Almacenado

ok, gracias por la ayuda prestada y listo voy a crear la secuencia de pasos de lo que debe realizar claramente

1. el sistema muestra las cuentas asociadas al id del comprobante seleccionado (son varias)
2. El usuario oprime un botón de mayorización
2.1 el sistema debe empezar a recorrer cada cuenta
2.2 el sistema debe verificar si la cuenta tiene o no centro de costo
2.2.1 Si la cuenta tiene centro de costo
2.2.1.1 Debe empezar a consultar el padre del centro costo -->102030 e insertar el registro con la cuenta -->11050503 ingresada hasta que el padre de centro de costo quede en NULL
2.2.1.2 Cuando termine de insertar con la cuenta -->11050503
2.2.1.3 Debe seguir el mismo proceso con el padre de la cuenta cuenta -->11050503 y asi sucesivamente hasta que el padre de la cuenta quede en NULL
2.2.2 Si la cuenta no tiene centro de costo
2.2.2.1 Debe insertar cuenta -->11050503 hasta que el padre de la cuenta quede en NULL

este es el proceso que se debe realizar debe quedar

con centro de costo

11050503 102030
11050503 102000
11050503 100000
11050503 Null
asi hasta que el codigo cuenta quede en 1

y si no tiene centro de costo
11050502 Null
110505 Null
1105 Null
11 Null
1 Null
  #13 (permalink)  
Antiguo 30/06/2015, 08:23
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Procedimiento Almacenado

Cita:
2.2.1.1 Debe empezar a consultar el padre del centro costo -->102030 e insertar el registro con la cuenta -->11050503 ingresada hasta que el padre de centro de costo quede en NULL
2.2.1.2 Cuando termine de insertar con la cuenta -->11050503
2.2.1.3 Debe seguir el mismo proceso con el padre de la cuenta cuenta -->11050503 y asi sucesivamente hasta que el padre de la cuenta quede en NULL
¿Insertar QUÉ?
Describe la operación para alguien que no sepa de qué estás hablando. Eso es crear un ECU (Especificación de CAso de Uso). Ten en cuenta que el desarrollador no sólo NO sabe de que hablas, sino que tampoco tiene por qué saberlo. El desarrollador sólo ve procesos y datos, no "cuentas".
La abstracción debe llegar al dato puro: ID del centro de costo, ID de cuenta, cómo se compone, cuantos dígitos representan un numero de cuenta, cual es el rango valido de ese ID y contra qué se valida.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #14 (permalink)  
Antiguo 30/06/2015, 12:19
Avatar de JeMaGa  
Fecha de Ingreso: julio-2011
Ubicación: Bogota
Mensajes: 430
Antigüedad: 12 años, 9 meses
Puntos: 4
Respuesta: Procedimiento Almacenado

tablas a utilizar
cabecera_comprobantes_2015_6
detalle_comprobantes_2015_6
saldos_contables_2015

1. mostrar todas las cuentas asociadas al id_cabecera_comprobantes_2015_6

Código MySQL:
Ver original
  1. SELECT detalle.id_cabecera, detalle.codigo_cuenta, detalle.sucursal, detalle.debito, detalle.credito, detalle.tercero, detalle.centrocosto FROM detalle_comprobantes_2015_6 as detalle HAVING detalle.id_cabecera = [id_cabecera_comprobantes_2015_6];

2. el usuario oprime el boton mayorizar
2.1 el sistema debe empezar a recorrer cada cuenta
Código MySQL:
Ver original
  1. SELECT codigo,movimiento,terceros,mayor,centrocosto FROM puc WHERE codigo = 11050503
2.2 el sistema debe verificar si la cuenta tiene o no centro de costo
2.2.1 Si la cuenta tiene centro de costo realiza consulta a la tabla saldos_contables_2015 para verificar si exite ya en la tabla, el centro de costo y la cuenta correspondiente o no
Código MySQL:
Ver original
  1. SELECT id FROM saldos_contables_2015 WHERE cuenta = 11050503 and tercero = NULL and centroCosto = 102030

si exite el centro de costo y la cuenta, lo que va hacer es actualizar el registro en la tabla saldos_contables_2015
Código MySQL:
Ver original
  1. UPDATE saldos_contables_2015 SET db_06 = 10000, cr_06 =10000 WHERE id = id_saldos_contables_2015;
si no
Código MySQL:
Ver original
  1. INSERT INTO saldos_contables_2015 (cuenta,tercero,sucursal,centroCosto,db_06,cr_06) VALUES(11050503,NULL,NULL, 102030, 10000,10000);
2.2.1.1 todo este proceso se debe realizar hasta que el centro de costo quede en NULL, cuando termine con esta cuenta debe realizar el mismo proceso con el padre de la

2.2.2 si la cuenta NO tiene centro de costo realiza el mismo proceso que en el punto 2.2.1 pero sin evaluar centro de costo
Código MySQL:
Ver original
  1. SELECT id FROM saldos_contables_2015 WHERE cuenta = 11050503 and tercero = NULL

2.2.2.1 se realiza
si exite la cuenta, lo que va hacer es actualizar el registro en la tabla saldos_contables_2015
Código MySQL:
Ver original
  1. UPDATE saldos_contables_2015 SET db_06 = 10000, cr_06 =10000 WHERE id = id_saldos_contables_2015;
si no
Código MySQL:
Ver original
  1. INSERT INTO saldos_contables_2015 (cuenta,tercero,sucursal,db_06,cr_06) VALUES(11100405,NULL,NULL, 10000,10000);
aqui me empieza a insertar el codigo de la cuenta en la tabla saldos_contables_2015 hasta que la cuenta quede en 1

Etiquetas: almacenado, campo, loop, php, procedimiento, registro, select, sql, tabla
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 20:38.