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

[SOLUCIONADO] error 1326 en fallos

Estas en el tema de error 1326 en fallos en el foro de Mysql en Foros del Web. Cordial Saludo, veo este error Error Code: 1325. Cursor is already open pero no tengo ningun cursor que no se hallan cerrado. ? @import url("http://static.forosdelweb.com/clientscript/vbulletin_css/geshi.css"); ...
  #1 (permalink)  
Antiguo 02/08/2014, 22:56
 
Fecha de Ingreso: febrero-2013
Ubicación: Cali Colombia
Mensajes: 118
Antigüedad: 11 años, 8 meses
Puntos: 0
Busqueda error 1326 en fallos

Cordial Saludo, veo este error Error Code: 1325. Cursor is already open
pero no tengo ningun cursor que no se hallan cerrado. ?

Código SQL:
Ver original
  1. USE almacen3;
  2. DROP PROCEDURE IF EXISTS  devuelve_informe_venta;
  3. DROP TABLE IF EXISTS informe;
  4.  DELIMITER |
  5. CREATE PROCEDURE devuelve_informe_venta(IN fecha_inicio DATE, IN fecha_final DATE)
  6.  
  7. BEGIN    
  8.    DECLARE fecha_factura DATE;
  9.    DECLARE codigo_factura INT DEFAULT 0;
  10.    DECLARE cod_producto INT DEFAULT 0;
  11.    DECLARE costo DOUBLE DEFAULT 0.0;
  12.    DECLARE total_registro INT DEFAULT 0;
  13.    DECLARE acumulador INT DEFAULT 0;
  14.    DECLARE nombre_producto VARCHAR(20);
  15.    DECLARE nit INT DEFAULT 0;
  16.    DECLARE v_control bool DEFAULT FALSE;
  17.  
  18.  
  19.    DECLARE crs_cod_fact CURSOR FOR SELECT fact_cod_fac,fact_fecha FROM Factura
  20.                         WHERE fact_fecha >= fecha_inicio AND fact_fecha <= fecha_final;
  21.    
  22.    DECLARE crs_cod_prod CURSOR FOR SELECT ord_cod_zap,pro_nomb,cal_cost,pro_nit FROM ord_compra oc, Producto p,Calzado c
  23.                       WHERE ord_cod_fact = codigo_factura;
  24.    
  25.  
  26.    
  27.    DECLARE CONTINUE HANDLER FOR NOT FOUND SET  v_control = TRUE;
  28.    CREATE  TABLE informe (num INT(5) AUTO_INCREMENT PRIMARY KEY,fecha DATE,cod_cal INT(10),nomb_cal VARCHAR(20),costo DECIMAL(6,2),nit INT(10))engine=memory;
  29.     OPEN crs_cod_fact;
  30.     crs_cod_fact_loop:loop
  31.         fetch crs_cod_fact INTO codigo_factura,fecha_factura;
  32.           IF v_control THEN
  33.               leave crs_cod_fact_loop;
  34.               close crs_cod_fact;
  35.           END IF;
  36.          
  37.          crs_cod_pro_loop:LOOP -- segundo LOOP donde realiza el la busqueda de nombre de productos, codigo y costo.
  38.             OPEN crs_cod_prod;
  39.             fetch crs_cod_prod INTO cod_producto, nombre_producto,costo,nit;
  40.             INSERT INTO informe VALUES('',fecha_factura,cod_producto,nombre_producto,costo,nit);
  41.             IF v_control THEN  
  42.                 close crs_cod_prod;
  43.                 leave crs_cod_pro_loop;
  44.             END IF;
  45.  
  46.          END LOOP crs_cod_pro_loop;
  47.     END LOOP crs_cod_fact_loop;
  48.    
  49.  
  50.    -- DROP Table if exists informe;
  51.  END;
  52. | delimiter ;
  53.   CALL devuelve_informe_venta(20140105,20140105);
  #2 (permalink)  
Antiguo 03/08/2014, 06:53
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 17 años
Puntos: 2658
Respuesta: error 1326 en fallos

Pues en realidad la respuesta es bastante simple: Estás abriendo el segundo cursor dentro del LOOP donde lo vas a usar, cuando deberías abrirlo fuera.
El segundo ciclo que se produzca intenta abrir nuevamente un cursor que ya está abierto.
Código MySQL:
Ver original
  1. crs_cod_pro_loop:LOOP
  2.    OPEN crs_cod_prod; -- Estas abriendo el cursor dentro del LOOP
  3.    fetch crs_cod_prod INTO cod_producto, nombre_producto,costo,nit;
  4.    INSERT INTO informe VALUES('',fecha_factura,cod_producto,nombre_producto,costo,nit);
  5.    IF v_control THEN  
  6.       close crs_cod_prod;
  7.       leave crs_cod_pro_loop;
  8.    END IF;
  9. END LOOP crs_cod_pro_loop;
Como notas adicionales, te recomiendo no crear tablas puras, ni tablas memory para uso temporal. Usa tablas TEMPORARY, en las que no se indica el ENGINE.
Extensivamente, yo ni siquiera usaría cursores para toda la tarea que haces, pero eso sería mi solución.
__________________
¿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 03/08/2014, 16:02
 
Fecha de Ingreso: febrero-2013
Ubicación: Cali Colombia
Mensajes: 118
Antigüedad: 11 años, 8 meses
Puntos: 0
Respuesta: error 1326 en fallos

Le agradezco el responder mis preguntas, veo que tiene un conocimiento muy amplio de los Mysql, pero digame si abro el cursor desde antes del loop podre hacer que por cada interaccion en el primer loop el segundo loop realize la busqueda comunmente, pues ese era mi idea de que cada interaccion del loop 1 realize en el loop 2 toda la busqueda.

Intente abrir el cursor antes del loop y no hubo resultados pues no hubo insercion en la tabla temporal.

Me causa curiosidad de como hacer este procedure sin Cursores, no sabria como .....
  #4 (permalink)  
Antiguo 04/08/2014, 06:39
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 17 años
Puntos: 2658
Respuesta: error 1326 en fallos

@andres18281:
Este tema, y este mismo procedimiento, ya ha sido motivo de otro post (que deberías haber continuado y no abriur uno nuevo), y en ese momento te hice algunas observaciones que por lo visto no has tenido mínimamente en cuenta...

Por lo pronto te hice la observación de que estás haciendo jOINs implícitos, pero no estás poniendo las condiciones de JOIN en el WHERE, por lo que existe riesgo potencial de que se generen productos cartesianos.
Por otro lado, ya te había dicho que yo veía innecesario el uso de cursores para recorrer el resultado de un join, cuyo origen era el resultado de otra consulta, simplemente para hacer inserciones. un JOIN más complejo es suficiente para el caso.
Además, ya te había mencionado que tablas TEMPORARY son más prácticas para lo que necesitas hacer.

En resumen la idea es esta:

- En primera instancia, lo que intentas resolver es obtener todas aquellas facturas que están en un determinado período de tiempo. Eso lo haces con esto:
Código MySQL:
Ver original
  1. SELECT fact_cod_fac, fact_fecha
  2. FROM Factura
  3. WHERE fact_fecha >= fecha_inicio AND fact_fecha <= fecha_final;
Yo aquí noto que podrías usar un BETWEEN para simplificar, pero eso es algo formal.
De esta consulta salen dos datos: Factura y fecha, y esos datos luego los recorres sólo para hacer eso:
Código MySQL:
Ver original
  1. SELECT ord_cod_zap,pro_nomb,cal_cost,pro_nit
  2. FROM ord_compra oc, Producto p, Calzado c
  3. WHERE ord_cod_fact = codigo_factura;
Esta segunda query tiene un problema: No se ve que haya una relación entre las tres tablas, o al menso no se está indicando.
Cuando MySQL se encuentra con eso, realiza una junta natural emparejando, implicitamente, aquellos campos que entre dos tablas tengan el mismo nombre. Esto puede tener efectos extraños si dos tablas tienen un campo llamado "id", "nombre", "fecha" o cualquier otro con identica denominación, sin importar si representan lo mismo.
¿Se entiende el riesgo?
Además, como de todos modos el filtro se aplica luego de realizar el JOIN implícito, estás haciendo un full table scan, que es una de las peores formas de consulta existentes, luego del producto cartesiano. Es muchísimo más eficiente usar JOIN explícitos, ya que estos sólo leen aquellos registros que coinciden entre tablas (especialmente cuando hay FKs definidas).

Bien, vamos a suponer que las tablas tienen bien distinguidos los nombres de sus campos, y que no se repiten entre tablas más que los nombres de las claves primarias y su respectiva referencia de clave foránea.
En ese contexto, la sintaxis debería ser:
Código MySQL:
Ver original
  1. SELECT ord_cod_zap,pro_nomb,cal_cost,pro_nit
  2. FROM ord_compra oc
  3.     INNER JOIN Producto p ON oc.pro_id = p.pro_id
  4.     INNER JOIN Calzado c ON p.pro_id = c.pro_id

Ahora bien, siendo que la query anterior devuelve fecha y numero de factura, y que lo que pareces querer es la fecha, para cada orden producto (calzado) vendido, las dos consultas bien podrían combinarse en una sola:
Código MySQL:
Ver original
  1. SELECT fact_fecha, ord_cod_zap, pro_nomb, cal_cost, pro_nit
  2. FROM Factura F
  3.     INNER JOIN ord_compra oc ON f.fact_cod_fac = oc.ord_cod_fact
  4.     INNER JOIN Producto p ON oc.pro_id = p.pro_id
  5.     INNER JOIN Calzado c ON p.pro_id = c.pro_id
  6. WHERE f.fact_fecha BETWEEN fecha_inicio AND fecha_final;
En ese contexto, una sola consulta estaría devolviendo todo lo que buscas, y con precisión.

- Por otro lado, planteas que quieres una tabla temporal donde insertar esos datos, pero usas una tabla MEMORY para eso.
te comento que las tablas MEMORY son tablas de estructura persistente, pero contenido volatil, por lo que luego de ejecutarse el proceso es probable que se enceuntre vacía. O al menos que se vacíe de datos al cerrarse la conexión que la usa.
Eso es así por feinición de la tabla.
Si lo que necesitas es una tabla, para luego consultarla en el acto, y que desaparezca, no necesitas una MEMORY, sino una TEMPORARY. Esta existe sólo durante la ejecucion del proceso, y se borra inmediatamente cuando termina.
Ahora bien, si no vas a matener persistencia del reporte, lo que te conviene es crear una temporary y usar el mismo SP para que devuelva la tabla resultado antes de que est desaparezca, o simplemente usar todo el SP para que ejecute la consulta.
Tu decides...

Yo, personalmente, intentaría algo parecido a esto:

Código MySQL:
Ver original
  1. CREATE PROCEDURE devuelve_informe_venta(IN fecha_inicio DATE, IN fecha_final DATE)
  2.     SET @id = 0;
  3.     CREATE TEMPORARY TABLE tablareporte AS
  4.     SELECT (@id:=@id+1)idreporte, fact_fecha, ord_cod_zap, pro_nomb, cal_cost, pro_nit
  5.     FROM Factura F
  6.         INNER JOIN ord_compra oc ON f.fact_cod_fac = oc.ord_cod_fact
  7.         INNER JOIN Producto p ON oc.pro_id = p.pro_id
  8.         INNER JOIN Calzado c ON p.pro_id = c.pro_id
  9.     WHERE f.fact_fecha BETWEEN fecha_inicio AND fecha_final;
  10.     SELECT *
  11.     FROM tablareporte;
  12.  END;
o bien simplemente:
Código MySQL:
Ver original
  1. CREATE PROCEDURE devuelve_informe_venta(IN fecha_inicio DATE, IN fecha_final DATE)
  2.     SET @id = 0;
  3.     SELECT (@id:=@id+1)idreporte, fact_fecha, ord_cod_zap, pro_nomb, cal_cost, pro_nit
  4.     FROM Factura F
  5.         INNER JOIN ord_compra oc ON f.fact_cod_fac = oc.ord_cod_fact
  6.         INNER JOIN Producto p ON oc.pro_id = p.pro_id
  7.         INNER JOIN Calzado c ON p.pro_id = c.pro_id
  8.     WHERE f.fact_fecha BETWEEN fecha_inicio AND fecha_final;
  9.  END;

Por supuesto, como ya te dije, estoy suponiendo las relaciones entre tus tablas, porque no las has explictado.
Pero yo haría algo así.

De hecho, casi todas las ocasiones donde he usado inicialmente cursores, termino utilizando tablas temporary, porque los cursores son ineficientes.

Com onota final, observo que en las condiciones de al menos uno de los IFs estás saliendo del LOOP antes de cerrar el cursor, por lo que el CLOSE al cursor jamás se ejecuta en esa instancia...
TEn cuidado con la lógica de ejecución.
__________________
¿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 04/08/2014, 15:48
 
Fecha de Ingreso: febrero-2013
Ubicación: Cali Colombia
Mensajes: 118
Antigüedad: 11 años, 8 meses
Puntos: 0
Respuesta: error 1326 en fallos

Gracias, ahora me ha quedado bien y con menos linea de codigo.

En verdad te agradezco....

Etiquetas: procedure
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 14:02.