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

Timeout al crear Procedimiento Almacenado en local

Estas en el tema de Timeout al crear Procedimiento Almacenado en local en el foro de Mysql en Foros del Web. Buenas tardes: Quería ver si me podían ayudar un con un procedimiento almacenado. En principio no me da error, pero al intentar 'cargarlo', me da ...
  #1 (permalink)  
Antiguo 23/02/2010, 13:37
 
Fecha de Ingreso: noviembre-2007
Mensajes: 154
Antigüedad: 16 años, 4 meses
Puntos: 2
Pregunta Timeout al crear Procedimiento Almacenado en local

Buenas tardes:

Quería ver si me podían ayudar un con un procedimiento almacenado.

En principio no me da error, pero al intentar 'cargarlo', me da un timeout, a pesar de ser en local.

He probado la carga por fichero y directamente copiándolo, pero nada.

El error que pone es:

Cita:
Fatal error: Maximum execution time of 300 seconds exceeded in Z:\wamp\apps\phpmyadmin3.2.0.1\libraries\import\sq l.php on line 259
No sé si realmente ese es el problema, o no, ya que me extraña que siendo en local, tras 5 minutos, aprox, dé el error. Lo achaco más a una incoherencia, que no llega a devolver un error.

La versión de MySQL es 5.1.36

Pongo el procedimiento, por si alguien encuentra algo raro, o piensa que se puede hacer mejor de otra manera.

Muchas gracias.



Código:
DELIMITER $$

CREATE PROCEDURE sp_insertarPresupuesto (idCliente int, fechaAlta datetime)

-- iniciamos el Procedimiento

BEGIN
	
	-- declaramos las variables
	declare idPresupuesto int;
	declare idCliente int;
	declare Referencia varchar(25);
	declare Detalle varchar(250);
	declare IVA int;
	declare PrecioUnitario decimal(5,2);
	declare Cantidad int;

	-- insertamos la cabecera del presupuesto
	INSERT INTO LM_Presupuestos values ('',idCliente, FechaAlta);
	
	-- recuperamos el idPresupuesto generado
	SET idPresupuesto := LAST_INSERT_ID();

	-- Comienza el cursor para insertar la tabla Detalle con los datos temporales
	-- declaramos el cursor
	DECLARE detallePrto CURSOR FOR
	
	-- capturamos los datos de la tabla temporal
    	select 
--            idPresupuesto,
    		idCliente,
    		Referencia,
    		Detalle,
    		IVA,
    		PrecioUnitario,
    		Cantidad
    	from LM_tmpPresupuestos;
	
	-- iniciamos CURSOR
    	OPEN detallePrto
	
	-- iniciamos el bucle
    
        REPEAT
    		FETCH next FROM detallePrto;
    		INTO idPresupuesto, idCliente, Referencia, Detalle, IVA, PrecioUnitario, Cantidad
    		WHILE @@fetch_status = 0    		
    		
    			INSERT INTO LM_detallePresupuesto values ('', idPresupuesto, idCliente, Referencia, Detalle, IVA, PrecioUnitario, Cantidad);    		
    	
        UNTIL done END REPEAT;
        
		CLOSE detallePrto;		
	
	-- se vacía la tabla temporal
	TRUNCATE TABLE LM_tmpPresupuestos;
	
-- finalizamos el Procedimiento

END

-- se usa el delimitador para indicar que se sale

$$

DELIMITER;
  #2 (permalink)  
Antiguo 23/02/2010, 13:48
 
Fecha de Ingreso: enero-2010
Ubicación: Sevilla
Mensajes: 202
Antigüedad: 14 años, 3 meses
Puntos: 5
Respuesta: Timeout al crear Procedimiento Almacenado en local

Creo que hay al menos dos problemas de sintaxis:
Código MySQL:
Ver original
  1. -- iniciamos CURSOR
  2.         OPEN detallePrto

Debería ser
Código MySQL:
Ver original
  1. -- iniciamos CURSOR
  2.         OPEN detallePrto;

Código MySQL:
Ver original
  1. FETCH next FROM detallePrto;
  2.             INTO idPresupuesto, idCliente, Referencia, Detalle, IVA, PrecioUnitario, Cantidad

Debería ser
Código MySQL:
Ver original
  1. FETCH next FROM detallePrto
  2.             INTO idPresupuesto, idCliente, Referencia, Detalle, IVA, PrecioUnitario, Cantidad;



No sé si habrá más cosas, pero prueba esto a ver si te funciona.

Lee la referencia aquí y revisa el código http://dev.mysql.com/doc/refman/5.0/en/cursors.html
__________________
Mi blog de temas más o menos técnicos

Y aquí el Jamón jamon de Jabugo
  #3 (permalink)  
Antiguo 23/02/2010, 15:34
 
Fecha de Ingreso: noviembre-2007
Mensajes: 154
Antigüedad: 16 años, 4 meses
Puntos: 2
Respuesta: Timeout al crear Procedimiento Almacenado en local

Buenas, muchas gracias por la rápida respuesta.

He probado y nada, ha seguido dando error, así que seguiré investigando.

Lo que he visto, es que la línea del 'error', hace referencia a los delimitadores y tiene su lógica entonces, ya que si no tiene claro cuáles son, se puede volver un poco loco.

Saludos.
  #4 (permalink)  
Antiguo 25/02/2010, 02:41
 
Fecha de Ingreso: noviembre-2007
Mensajes: 154
Antigüedad: 16 años, 4 meses
Puntos: 2
Respuesta: Timeout al crear Procedimiento Almacenado en local

Buenos días:
Se me ha planteado la cuestión, de si para este caso en concreto sería mejor utilizar un trigger. La idea principal, aunque aún no lo he añadido, es meterlo en un commit/rollback, por control de posibles fallos.
Muchas gracias.
Saludos.
  #5 (permalink)  
Antiguo 25/02/2010, 05:20
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: Timeout al crear Procedimiento Almacenado en local

En mi opinión el SP está haciendo demasiadas tareas inutilmente.
Básicamente (y esta es la forma que manejo algunas con el mismo objetivo), esto se puede resolver con un SP que ejecuta tres sentencias y un trigger para poner los valores de subítem (eso si el valor no viene en la tabla temporal misma).
La sintaxis de este ejemplo recibe tres parámetros, devolviendo en el tercero un valor mayor a cero si se pudo realizar, o bien cero sino se pudo, ya que devuelve el LAST_INSERT_ID().
Nota: Estoy suponiendo, para este caso, que los campos de la tabla destino se llaman igual que en la tabla origen.
Código MySQL:
Ver original
  1. DELIMITER $$
  2.  
  3. CREATE PROCEDURE sp_insertarPresupuesto (IN idCliente INT, IN fechaAlta DATETIME, INOUT idPresupuesto INT)
  4.  
  5. -- iniciamos el Procedimiento
  6.  
  7.  
  8.     -- insertamos la cabecera del presupuesto
  9.     INSERT INTO LM_Presupuestos values ('',idCliente, FechaAlta);
  10.  
  11.     -- recuperamos el idPresupuesto generado
  12.     SET idPresupuesto = LAST_INSERT_ID();
  13.   IF idPresupuesto > 0 THEN
  14.     -- capturamos los datos de la tabla temporal
  15.     INSERT INTO LM_detallePresupuesto(
  16.       idPresupuesto,
  17.       idCliente,
  18.       Referencia,
  19.       Detalle,
  20.       IVA,
  21.       PrecioUnitario,
  22.       Cantidad)
  23.     SELECT
  24.       idPresupuesto,
  25.       idCliente,
  26.       Referencia,
  27.       Detalle,
  28.       IVA,
  29.       PrecioUnitario,
  30.       Cantidad
  31.     FROM LM_tmpPresupuestos;
  32.     -- se vacía la tabla temporal
  33.       TRUNCATE TABLE LM_tmpPresupuestos;
  34.     END IF;
  35.  
  36. $$
  37.  
  38. DELIMITER;

Si los valores de subitem recibidos no vienen de la tabla origen, entonces hay que poner un TRIGGER similar a este:
Código MySQL:
Ver original
  1. CREATE TRIGGER SET_SUBITEM_PRESUPUESTOS BEFORE INSERT
  2. ON  LM_detallePresupuesto
  3.         IF(SELECT MAX(SUBITEM) FROM  LM_detallePresupuesto WHERE idPresupuesto=NEW.idPresupuesto) IS NULL THEN
  4.       SET NEW.SUBITEM = 1;
  5.     ELSE
  6.       SET NEW.SUBITEM = (SELECT MAX(SUBITEM) FROM  LM_detallePresupuesto WHERE idPresupuesto=NEW.idPresupuesto) + 1;
  7.     END IF;
  8. END$$
  9.  
  10. DELIMITER ;
Obviamente, este script hace referencia a un campo "SUBITEM" que debería existir, o llamarse de otra forma.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #6 (permalink)  
Antiguo 25/02/2010, 06:20
 
Fecha de Ingreso: noviembre-2007
Mensajes: 154
Antigüedad: 16 años, 4 meses
Puntos: 2
Respuesta: Timeout al crear Procedimiento Almacenado en local

Buenos días:

Lo primero de todo, muchas gracias, ahora tengo que asimilarlo con calma en casa.

De todas maneras me han surgido un par de dudas/consultas:
1- la tabla temporal y la final de detalle, no tienen los mismos campos, ya que la primera la relleno sin idPresupuesto ( por si interesa, tengo planteado cómo lo relleno en: http://www.forosdelweb.com/f127/cons...racias-774188/ ). El tema es que idPresupuesto se forma después del registro de la cabecera.

2- No me queda claro el concepto de 'SUBITEM' en general. Hasta ahora no había utilizado nada de todo esto, ya que lo hacía directamente por código, pero me parece más estable hacerlo en BBDD directamente, sobretodo, si tengo la posibilidad de ponerle un rollBack, por cualquier posible fallo de conexión, durante el proceso, que me podría dejar presupuestos 'rotos'.

De todas maneras, cuando llegue a casa, me sentaré a 'meditarlo' y a 'asimilarlo'.

Muchas gracias de nuevo.

Saludos.
  #7 (permalink)  
Antiguo 25/02/2010, 07:38
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: Timeout al crear Procedimiento Almacenado en local

Cita:
Iniciado por jesusjj Ver Mensaje
Buenos días:

Lo primero de todo, muchas gracias, ahora tengo que asimilarlo con calma en casa.

De todas maneras me han surgido un par de dudas/consultas:
1- la tabla temporal y la final de detalle, no tienen los mismos campos, ya que la primera la relleno sin idPresupuesto ( por si interesa, tengo planteado cómo lo relleno en: http://www.forosdelweb.com/f127/cons...racias-774188/ ). El tema es que idPresupuesto se forma después del registro de la cabecera.

2- No me queda claro el concepto de 'SUBITEM' en general. Hasta ahora no había utilizado nada de todo esto, ya que lo hacía directamente por código, pero me parece más estable hacerlo en BBDD directamente, sobretodo, si tengo la posibilidad de ponerle un rollBack, por cualquier posible fallo de conexión, durante el proceso, que me podría dejar presupuestos 'rotos'.

De todas maneras, cuando llegue a casa, me sentaré a 'meditarlo' y a 'asimilarlo'.

Muchas gracias de nuevo.

Saludos.
En esencia, un presupuesto, es un documento similar a una factura con la diferencia que no tiene valor contable, y por lo tanto no genera transacciones en Caja, Banco, Cuentas a Cobrar, recibos, ni ningún otro tipo de documento que implique transacciones de valores.
Pero tiene similitudes en al menos dos cosas:
1. Contiene los datos del cliente o destinatario, con sus datos de número de presupuesto, fecha y opcionalmente condiciones impositivas del cliente.
2. Contiene un listado de items que se estén presupuestando, sean estos servicios o productos.
Esto implica que hay al menos dos tablas involucradas en la generación de un presupuesto: Presupuesto y Presupuesto_Detalle, por darles algún nombre.
Ahora bien, al igual que en la factura, un mismo registro de Prespuesto debe estar relacionado con uno o más de Presupuesto_detalle. Esto quiere decir que el número de presupuesto debe estar en los registros del detalle como FK. El problema es cómo hacer para identificar unívocamente los registros del detalle. Hay al menos dos formas
- Puedes usar el ID del producto o servicio. Es funcional, siempre y cuando no se pongan en el mismo presupuesto dos veces los mismos productos con diferencias de precios o cantidades, cosa que en un presupuesto es posible dadas ciertas circunstancias (como descuentos, ofertas y otras cosas así).
- Puedes numerar las líneas del presupuesto. Es lo más simple y no produce ningún tipo de problemas respecto al contenido.
Así pues, la PK de Presupuesto_detalle debería ser: nroPrespuesto + nroSubItem.

¿Se comprende la idea?

Cita:
1- la tabla temporal y la final de detalle, no tienen los mismos campos, ya que la primera la relleno sin idPresupuesto (...). El tema es que idPresupuesto se forma después del registro de la cabecera.
Eso no tiene absolutamente ninguna importancia. El SP que te propongo inserta primero el registro en presupuesto e inmediatamente recupera el ID creado, asignándolo al mismo campo INOUT del prototipo del SP. Con eso, no solamente lo genera, sino que lo devuelve.
Luego lo pone como constante en el nuevo INSERT... SELECT..., éste último debe ser específico y poner dos valores como constantes: el ID del presupuesto y cero (0) para el subitem, y en la tabla hay que indicar los campos que se insertarán (hay una forma de hacer que la numeración se genere en el mismo SELECT). Al insertarse los registros, el TRIGGER los irá numerando uno por uno en la medida que van llegando a la tabla.

Puedo asegurarte que el método es funcional. Lo uso hasta con tablas de 10.000 registros y ni pestañea.

El único secreto es cómo manejarás la transacción: o la haces dentro del SP, o la invocas antes de llamarlo, en la aplicación.
Eso es una decisión de diseño: hazlo como quieras, de todos modos funcionará.

__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #8 (permalink)  
Antiguo 26/02/2010, 10:45
 
Fecha de Ingreso: noviembre-2007
Mensajes: 154
Antigüedad: 16 años, 4 meses
Puntos: 2
Respuesta: Timeout al crear Procedimiento Almacenado en local

Buenas tardes:

No he podido probar lo que me aconsejaron, pero esta tarde quiero dedicarle un rato.

Antes de nada, voy a comentar cómo está montado hasta ahora, porque encaja en la 'definición' que propuesta.

Para el alta de presupuestos, se utilizan tres tablas:

1- Cabecera, que recoge el idCliente (asociado a la tabla de clientes), la fecha de alta del presupuesto y el autonumérico para el idPresupuesto.

2- Temporal, recoge los datos registrados, mientras se define el presupuesto. En esta se registra la referencia, el detalle o descripción, la cantidad, el precio unitario y el impuesto (porcentaje), así como el idDetalle, para el control y posible edición o borrado de línea.

3- Por último, está la de detalle, que es donde se vuelca la anterior. Tiene los mismo campos, pero además incluye el idPresupuesto y no recuerdo si añadí el idCliente.

Lo único que no termino de entender es la parte:
Cita:
Si los valores de subitem recibidos no vienen de la tabla origen, entonces hay que poner un TRIGGER similar a este:

Código MySQL:
Ver original
  1. CREATE TRIGGER SET_SUBITEM_PRESUPUESTOS BEFORE INSERT
  2. ON  LM_detallePresupuesto
  3.         IF(SELECT MAX(SUBITEM) FROM  LM_detallePresupuesto WHERE idPresupuesto=NEW.idPresupuesto) IS NULL THEN
  4.       SET NEW.SUBITEM = 1;
  5.     ELSE
  6.       SET NEW.SUBITEM = (SELECT MAX(SUBITEM) FROM  LM_detallePresupuesto WHERE idPresupuesto=NEW.idPresupuesto) + 1;
  7.     END IF;
  8. END$$
  9.  
  10. DELIMITER ;
  11. Obviamente, este script hace referencia a un campo "SUBITEM" que debería existir, o llamarse de otra forma.
El concepto de 'subitem', supongo que será una especie de variable contandor para cada línea del bucle. Pero no entiendo exactamente el:
Cita:
Si los valores de subitem recibidos no vienen de la tabla origen,
A qué te refieres con no vienen de la tabla origen.

Muchas gracias por todo y esta tarde a ver qué progresos hago. También quiero meterlo en un trans commit o rollback, para evitar desastres ante posibles cortes de conexión en pleno registro

Un saludo.
  #9 (permalink)  
Antiguo 26/02/2010, 11:02
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: Timeout al crear Procedimiento Almacenado en local

Cita:
A qué te refieres con no vienen de la tabla origen.
A que si en la tabla que guarda temporalmente el detalle que se ingresará en la tabla final, las lineas están numeradas de 1 en 1 secuencialmente. Esos son los números de subitem.
En ese caso el datos vuelca sin más en a tabla de detalle.

Por cierto, en la tabla de detalle el dato de IdCliente es redundante, porque su vinculación está dada por la otra tabla de la que el detalle depende.
Repetir datos innecesariamente es un error grave en el modelo E-R..
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #10 (permalink)  
Antiguo 27/02/2010, 04:23
 
Fecha de Ingreso: noviembre-2007
Mensajes: 154
Antigüedad: 16 años, 4 meses
Puntos: 2
Respuesta: Timeout al crear Procedimiento Almacenado en local

Buenos días:

Al final he conseguido cargarlo, aunque a través de HeidiSQL y de Navicat. Con PHPMyAdmin ha sido totalmente imposible y lo he probado todo, pero bueno Seguiré intentándolo, por localizar el fallo, ya que he probado quitando y poniendo delimitadores, modificando los del input, ...

De todas maneras ya funciona y puedo continuar.

Muchas gracias.

Saludos
  #11 (permalink)  
Antiguo 27/02/2010, 06:56
 
Fecha de Ingreso: noviembre-2007
Mensajes: 154
Antigüedad: 16 años, 4 meses
Puntos: 2
Respuesta: Timeout al crear Procedimiento Almacenado en local

Buenas, al final lo subí a PHPMyAdmin de la siguiente forma:

Código MySQL:
Ver original
  1. CREATE PROCEDURE sp_insertarPresupuesto (IN idCliente INT, IN fechaAlta DATETIME, INOUT idPresupuesto INT)
  2. INSERT INTO LM_Presupuestos VALUES ('',idCliente,fechaAlta);
  3. SET idPresupuesto = LAST_INSERT_ID();
  4. IF idPresupuesto > 0 THEN
  5. INSERT INTO LM_detallePresupuesto (idPresupuesto,idCliente,Referencia,Detalle,IVA,PrecioUnitario,Cantidad)
  6. SELECT idPresupuesto,idCliente,Referencia,Detalle,IVA,PrecioUnitario,Cantidad FROM LM_tmpPresupuestos;
  7. TRUNCATE TABLE lm_tmpPresupuestos;

Y modificando el input del delimitador por cualquier otra cosa.

Saludos

Etiquetas: cursor, procedimiento, procedure, store, almacenar
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 11:16.