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

[SOLUCIONADO] ¿Qué estoy haciendo mal? [Procedimiento almacenado]

Estas en el tema de ¿Qué estoy haciendo mal? [Procedimiento almacenado] en el foro de Mysql en Foros del Web. Hola a todos, Soy yo nuevamente, esta vez mi problema es el siguiente: Después de unas cuantas horas leyendo acerca de los procedimiento almacenados, he ...
  #1 (permalink)  
Antiguo 09/06/2014, 22:35
 
Fecha de Ingreso: junio-2014
Mensajes: 18
Antigüedad: 10 años, 6 meses
Puntos: 0
Pregunta ¿Qué estoy haciendo mal? [Procedimiento almacenado]

Hola a todos,

Soy yo nuevamente, esta vez mi problema es el siguiente:

Después de unas cuantas horas leyendo acerca de los procedimiento almacenados,
he creado uno propio, el objetivo de mi procedimiento es añadir un nuevo usuario a una tabla (Usuarios) o modificar (dependiendo de cómo mande a llamar dicho procedimiento).

Cada usuario nuevo obtiene una id automáticamente (incrementandole un 1 al número de la id del último registro).

Funciona bien cuando se trata de agregar al primer usuario con la id 0 en la tabla, lo mismo con el segundo usuario con la id 1, pero al querer insertar el tercer usuario con la id 2 es donde me bloqueo... Pues me quiere agregar el tercer usuario con la id 1.

Mi procedimiento almacenado es el siguiente:

Código SQL:
Ver original
  1. CREATE PROCEDURE CrearUsuario (IN idx CHAR(9), IN nombrex VARCHAR(25), IN apellidox VARCHAR(25), IN edadx INT(2), IN generox CHAR(1), IN ciudadx VARCHAR(30), IN estadox VARCHAR(30), IN paisx VARCHAR(30))
  2. BEGIN
  3.     IF (idx = "Agregar") THEN
  4.         SET @numUsuario = (SELECT MAX(id) FROM Usuarios);
  5.         SET @numUsuario = IF(@numUsuario IS NULL, 0, @numUsuario + 1);
  6.         INSERT INTO Usuarios(id, nombre, apellido, edad, genero, ciudad, estado, pais) VALUES(@numUsuario, nombrex, apellidox, edadx, generox, ciudadx, estadox, paisx);
  7.     ELSE
  8.         UPDATE Usuarios SET nombre = nombrex, apellido = apellidox, edad = edadx, genero = generox, ciudad = ciudadx, estado = estadox, pais = paisx WHERE id = idx;
  9.     END IF;
  10. END$$


Espero sus respuestas, gracias.

Última edición por gnzsoloyo; 11/06/2014 a las 06:42 Razón: Usar HIGHLIGHT "SQL", por favor.
  #2 (permalink)  
Antiguo 11/06/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: ¿Qué estoy haciendo mal? [Procedimiento almacenado]

Primer consejo: No estás escribiendo PHP, sino SQL. Si un parámetro de entrada se usa como entero, no debes ingresar por él nada que no sean enteros. Nada.
El parámetro "idx" lo estás usando tanto para ingresar "Agregar" como el numero de ID del usuario, y eso es un error conceptual. O es una cosa, o es la otra, pero no debes usarlo para ambas posibilidades.
Además, tampoco lo necesitas como caracter, porque simplemente conque entre el numero, o un cero, puedes contar cuantos registros hay con ese ID y si no devuelve ninguno es que hay qe agregar el usuario (no debe existir jamás un ID cero en la tabla, eso es absurdo).
Por otro lado, a menos que vayas a usar el numero del nuevo usuario fuera del SP inmediatamente, y no se cierre la conexión a la base en ningún momento, no conviene usar variables de usuario global de MySQL, sino locales del SP.
Si lo que necesitas es recuperar el ID generado, simplemente le pones un SELECT numUsuario al final, y la ejecución del SP te devolverá por resultado el numero generado.

La idea sería mas o menos así:
Código MySQL:
Ver original
  1. CREATE PROCEDURE CrearUsuario (
  2.     IN idx CHAR(9),
  3.     IN nombrex VARCHAR(25),
  4.     IN apellidox VARCHAR(25),
  5.     IN edadx INT(2),
  6.     IN generox CHAR(1),
  7.     IN ciudadx VARCHAR(30),
  8.     IN estadox VARCHAR(30),
  9.     IN paisx VARCHAR(30))
  10.     DECLARE numUsuario INT DEFAULT 0;
  11.     IF (SELECT count(1) FROM Usuarios WHERE id = idx) = 0 THEN
  12.         SELECT MAX(id) FROM Usuarios INTO numusuario;
  13.         SET numUsuario = numUsuario + 1;
  14.         INSERT INTO Usuarios(id, nombre, apellido, edad, genero, ciudad, estado, pais)
  15.         VALUES(numUsuario, nombrex, apellidox, edadx, generox, ciudadx, estadox, paisx);
  16.     ELSE
  17.         UPDATE Usuarios
  18.           SET nombre = nombrex,
  19.           apellido = apellidox,
  20.           edad = edadx,
  21.           genero = generox,
  22.           ciudad = ciudadx,
  23.           estado = estadox,
  24.           pais = paisx
  25.         WHERE id = idx;
  26.     END IF;
  27.     SELECT numUsuario;
  28. END$$
__________________
¿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 13/06/2014, 17:51
 
Fecha de Ingreso: junio-2014
Mensajes: 18
Antigüedad: 10 años, 6 meses
Puntos: 0
Respuesta: ¿Qué estoy haciendo mal? [Procedimiento almacenado]

Gracias nuevamente por tu respuesta, gnzsoloyo.

He mirado el SP que colocaste y lo probé pero me daba el siguiente error:

#1048 - Column 'id' cannot be null

Analicé bien el código y probé modificando la siguiente línea:

SELECT MAX(id) FROM Usuarios INTO numusuario;

por esta:

SELECT MAX(id) FROM Usuarios;

Entonces, ahí si me funcionó el SP cuando agregué el primer registro a la tabla Usuarios.

Después intenté agregar otro registro y ya no me dejaba por lo mismo del error que me salía con mi SP:

#1062 - Duplicate entry '1' for key 'PRIMARY'
  #4 (permalink)  
Antiguo 14/06/2014, 16: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: 17 años
Puntos: 2658
Respuesta: ¿Qué estoy haciendo mal? [Procedimiento almacenado]

Cita:
#1048 - Column 'id' cannot be null
Eso se puede dar en el contexto de ese SP si y sólo si la tabla está vacía. Cuando ya existe al menos un registro eso no se puede dar, si se usa:

Código SQL:
Ver original
  1. SELECT MAX(id) FROM Usuarios INTO numusuario;

Para resolverlo no hay que haer lo que hiciste, porque se genera una duplicidad de datos. Lo que corresponde es verificar si la variable se volvió nula...

Código MySQL:
Ver original
  1. CREATE PROCEDURE CrearUsuario (
  2.     IN idx CHAR(9),
  3.     IN nombrex VARCHAR(25),
  4.     IN apellidox VARCHAR(25),
  5.     IN edadx INT(2),
  6.     IN generox CHAR(1),
  7.     IN ciudadx VARCHAR(30),
  8.     IN estadox VARCHAR(30),
  9.     IN paisx VARCHAR(30))
  10.     DECLARE numUsuario INT DEFAULT 0;
  11.     IF (SELECT count(1) FROM Usuarios WHERE id = idx) = 0 THEN
  12.         SELECT MAX(id) FROM Usuarios INTO numusuario;
  13.         -- Controlando que sea nulo, y por tanto la tabla este vacia.
  14.         SET numUsuario = IFNULL(numUsuario, 0) + 1;
  15.         INSERT INTO Usuarios(id, nombre, apellido, edad, genero, ciudad, estado, pais)
  16.         VALUES(numUsuario, nombrex, apellidox, edadx, generox, ciudadx, estadox, paisx);
  17.     ELSE
  18.         UPDATE Usuarios
  19.           SET nombre = nombrex,
  20.           apellido = apellidox,
  21.           edad = edadx,
  22.           genero = generox,
  23.           ciudad = ciudadx,
  24.           estado = estadox,
  25.           pais = paisx
  26.         WHERE id = idx;
  27.     END IF;
  28.     SELECT numUsuario;
  29. END$$

Para que se entienda: NULL no es un valor, es un estado. Pero toda operación de suma, multiplicación, división, resta, o concatenación de cualquier valor con NULL, da... NULL.
Entre esas situaciones está que MAX(), MIN(), AVG(), aplicado sobre una tabla sin registros, o una consulta que no devuelve registros, da pro resultado NULL.
Además, el hecho de que inicialices una variable con un valor por default, no implica que el valor se conserve si (como en este caso), le terminas asignando un resutlado NULL. En ese caso prevalece el NULL, y por eso se rompe todo.
La solución es sencilla: Debes controlar toda posibilidad de que se presente el NULL y no hacer operaciones con valores así.

Nota final: Como NULL no es un dato, tampoco se pueden usar operadores lógicos con el, sólo se puede verificar si es o no nulo. Por eso en ciertas ocasiones puede ser conveniente usar IF EXISTS, IS NULL o IS NOT NULL, para validar el resultado de consultas y subconsultas.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)

Última edición por gnzsoloyo; 14/06/2014 a las 16:50
  #5 (permalink)  
Antiguo 15/06/2014, 10:59
 
Fecha de Ingreso: junio-2014
Mensajes: 18
Antigüedad: 10 años, 6 meses
Puntos: 0
Respuesta: ¿Qué estoy haciendo mal? [Procedimiento almacenado]

Muchísimas gracias, gnzsoloyo, muy buenas y claras tus explicaciones.

Saludos :D

Etiquetas: haciendo, null, procedimiento, registro, select, tabla, usuarios
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 08:32.