MySQL - Error al Inserta un registro en mysql

 
Vista:
sin imagen de perfil
Val: 102
Bronce
Ha disminuido 1 puesto en MySQL (en relación al último mes)
Gráfica de MySQL

Error al Inserta un registro en mysql

Publicado por Miguel (60 intervenciones) el 20/06/2018 22:25:24
Este es el procedimiento

1
2
3
4
5
6
7
8
9
10
11
12
CREATE DEFINER=`root`@`localhost` PROCEDURE `delete`(
IN Tabla varchar(10),
IN Campo varchar(15),
IN txtCampo varchar(50)
)
BEGIN
#  not working with where.
set @sql = concat('delete from ',Tabla,' where ',Campo, '=', txtCampo);
# ---- not working with where 
prepare stm from @sql;
execute stm;
END

El error en el Dele "desconocida la columna -nombre del campo- en la clausula Where.

Los datos introducidos son _ El nombre de la tabla
El campo Primary
El texto del campo a eliminar.

Quizá alguien me diga que faltan comillas pero la verdad es que tengo otros procedimientos sin comillas en los campos y funcionan bien. Como este que les pongo

1
2
3
4
5
6
7
8
9
10
CREATE DEFINER=`root`@`localhost` PROCEDURE `VerCalles`(
	IN Calle VARCHAR(50)
)
BEGIN
	SET @VV_CONSDINAM = CONCAT('SELECT * FROM ',Calle);
        -- Preparamos la sentencia
        PREPARE SENTENCIA FROM @VV_CONSDINAM;
        -- La ejecutamos
        EXECUTE SENTENCIA;
END

Gracias
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
sin imagen de perfil
Val: 953
Oro
Ha mantenido su posición en MySQL (en relación al último mes)
Gráfica de MySQL

Error al Inserta un registro en mysql

Publicado por leonardo_josue (414 intervenciones) el 21/06/2018 17:49:11
Hola Miguel:

Tu procedimiento no tiene nada de malo, pero el mensaje de error es claro: el nombre del campo que estás enviando no existe en la tabla a la que haces referencia: aquí una muestra de que tu SP funciona correctamente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
mysql> DROP PROCEDURE IF EXISTS delete_registro;
Query OK, 0 rows affected (0.00 sec)
 
mysql> DELIMITER $$
mysql> CREATE
    -> PROCEDURE delete_registro(
    -> IN Tabla VARCHAR(10),
    -> IN Campo VARCHAR(15),
    -> IN txtCampo VARCHAR(50)
    -> )
    -> BEGIN
    -> #  not working with where.
    -> SET @SQL = CONCAT('delete from ',Tabla,' where ',Campo, '=', txtCampo);
    -> # ---- not working with where
    -> PREPARE stm FROM @SQL;
    -> EXECUTE stm;
    -> END$$
Query OK, 0 rows affected (0.00 sec)
 
mysql> DELIMITER ;
mysql> SELECT * FROM tabla;
+--------+--------+--------+
| campo1 | campo2 | campo3 |
+--------+--------+--------+
|     34 |     10 |    340 |
|     12 |      5 |     60 |
|     10 |     10 |    100 |
+--------+--------+--------+
3 rows in set (0.00 sec)
 
mysql> CALL delete_registro('tabla', 'campo1', '12');
Query OK, 1 row affected (0.10 sec)
 
mysql> SELECT * FROM tabla;
+--------+--------+--------+
| campo1 | campo2 | campo3 |
+--------+--------+--------+
|     34 |     10 |    340 |
|     10 |     10 |    100 |
+--------+--------+--------+
2 rows in set (0.00 sec)

Entonces, revisa los parámetros que estás enviando al SP y la misma recomendación que te hice en el otro post, verifica cómo queda conformado tu SQL antes de la ejecución...

1
2
Quizá alguien me diga que faltan comillas pero la verdad es que tengo
otros procedimientos sin comillas en los campos y funcionan bien.

Mucho Ojo, debes de tener cuidado si los campos con los que vas a trabajar son de tipo VARCHAR o fecha, ya que ahí si tienes que considerar las comillas, por ejemplo, si tu campo es de tipo fecha, tal como estás formando el SQL, el delete podría quedar así:

1
DELETE FROM tabla WHERE campo = 2018-06-21

cuando lo correcto debería ser así:

1
DELETE FROM tabla WHERE campo = '2018-06-21'

¿Se entiende?

Finalmente te hago una recomendación: veo que haces mucho uso sentencias preparadas lo cual es muy peligroso (al menos como lo estás haciendo) ya que te expones a un ataque de SQL Inyection, ¿a qué me refiero con esto? checa este ejemplo con tu propio SP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> SELECT * FROM tabla;
+--------+--------+--------+
| campo1 | campo2 | campo3 |
+--------+--------+--------+
|     34 |     10 |    340 |
|     12 |      5 |     60 |
|     10 |     10 |    100 |
+--------+--------+--------+
3 rows in set (0.00 sec)
 
mysql> CALL delete_registro('tabla', 'campo1', '12 OR 1 = 1');
Query OK, 3 rows affected (0.07 sec)
 
mysql> SELECT * FROM tabla;
Empty set (0.00 sec)

Observa que en este caso el parámetro para el valor del CAMPO estoy enviando '12 or 1 = 1' de tal suerte que tu sentencia queda así:

1
DELETE FROM tabla WHERE campo = 12 OR 1 = 1;

La cual es perfectamente válida y hace que se borren todos los registros de la tabla:

Debes de tener mucho cuidado con el uso de este tipo de consultas y es más yo te recomendaria NO USES SENTENCIAS PREPARADAS DE ESTA MANERA. Y si de plano, tienes que hacer uso de sentencias así, dale un vistazo a cómo puedes evitar estos ataques.

https://tinyurl.com/yd5gk6pu

Finalmente, una recomendación: cuando nombres tus objetos de BD's como tablas, procedimientos almacenados, funciones, etc. EVITA LLAMARLOS CON PALABRAS RESERVADAS. En tu ejemplo tu SP se llama DELETE y el problema creo que es obvio.

Saludos
Leo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 102
Bronce
Ha disminuido 1 puesto en MySQL (en relación al último mes)
Gráfica de MySQL

Error al Inserta un registro en mysql

Publicado por Miguel (60 intervenciones) el 21/06/2018 22:10:18
Muchas gracias por tus observaciones he visto los ejemplos y entiendo que lo que me indica un ejemplo es no utilizar "varchar" y usar "SqlDbType.VarChar" para evitar los ataques.

Lo que no entiendo es lo de no usar SP, si te diría que he visto unas 50 páginas de mysql para ver diferente ejemplos de esto y que al final con la orientación de Cesar un forero he llegado hacer estos procedimientos. si ahora de repente me dices que no es aconsejable por los problemas que comentas directamente me tiro al mar con una piedra al cuello pues me ha costado 6 meses ver que era el mysql y el mariaçDB y hacer una serie de casos de Insertar, borrar, modificar y visualizar y hacer un programa Visual Studio.

Meditare todo detenidamente y a lo mejor llego a la conclusión de que es mejor emplear el tiempo en otra cosa pues en este mundillo si ya me resulta duro avanzar y ademas me encuentro con problemas de ataques informáticos igual me hecho una huerta en el campo y espero que no me salgan topos.

Gracias y un saludo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 92
Ha mantenido su posición en MySQL (en relación al último mes)
Gráfica de MySQL

Error al Inserta un registro en mysql

Publicado por Cesar (28 intervenciones) el 21/06/2018 22:54:36
Hola.

Si esta bien usar SP, y de hecho es mas recomendable por seguridad.

Lo que se refiere Leonardo, es no armar las consultas SQL dentro del SP, como las esta armando, ya que, por ejemplo, si alguien hace algo como esto:

1
CALL delete_registro('tabla', 'campo1', '12 OR 1 = 1');

podria borrar toda su tabla.

Lo que debe enviar en los parametros, son valores, y validar/usar dichos valores dentro del SP.

Saludos.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 102
Bronce
Ha disminuido 1 puesto en MySQL (en relación al último mes)
Gráfica de MySQL

Error al Inserta un registro en mysql

Publicado por Miguel (60 intervenciones) el 21/06/2018 22:58:35
Te refieres a no poner los nombres reales de los campo?

Un saludo y gracias
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 953
Oro
Ha mantenido su posición en MySQL (en relación al último mes)
Gráfica de MySQL

Error al Inserta un registro en mysql

Publicado por leonardo_josue (414 intervenciones) el 21/06/2018 23:35:46
Hola de nuevo Miguel:

1
Lo que no entiendo es lo de no usar SP,

Ojo, yo nunca dije que no utilizaras SP, tal como dice Cesar lo que yo te digo es que no uses SENTENCIAS PREPARADAS, al menos no como lo estás haciendo.

coincido con Cesar cuando dice que por cuestiones de seguridad es mejor usar Procedimientos Almacenados que hacer operaciones de BD's (Update's, Delete's, Insert's) directamente, entre otras cosas para hacer las validaciones pertinentes para cada caso. Lo que no está bien es que abuses de las sentencias preparadas por tratarte de ahorrar algo de código.

Quiero imaginar que la razón para que trates de hacer un procedimiento para borrar "dinámicamente" registros de una tabla es para no tener que hacer un SP para cada tabla que utilices, pero ahí es donde está el problema, ya que te expones a lo que ya te puse. En tu caso, es preferible que no hagas un SP "genérico" para todas las tablas, sino que hagas tantos SP como tablas necesites borrar, de tal suerte que tu SQL no sea tan "abierto". Además, es recomendable armar los parámetros con USING, no concatenando cadenas, es decir, algo así:

En lugar de armar el DELETE genérico, utiliza un DELETE exclusivo para una tabla:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> DELIMITER $$
mysql> DROP PROCEDURE IF EXISTS delete_registro_tabla$$
Query OK, 0 rows affected (0.02 sec)
mysql> CREATE PROCEDURE delete_registro_tabla(
    -> IN txtCampo VARCHAR(50)
    -> )
    -> BEGIN
    ->   SET @campo = txtCampo;
    ->   PREPARE stm FROM 'delete from tabla where campo1 = ?';
    ->   EXECUTE stm USING @campo;
    ->   DEALLOCATE PREPARE stm;
    -> END$$
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;

Observa que en lugar de contatenar directamente el valor del campo, utilizo el ? para indicar que se enviará como parámetro. ahora observa como se comporta el CALL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mysql> SELECT * FROM tabla;
+--------+--------+--------+
| campo1 | campo2 | campo3 |
+--------+--------+--------+
|     10 |     12 |    120 |
|     13 |      1 |     13 |
|     12 |      5 |     60 |
+--------+--------+--------+
3 rows in set (0.00 sec)
 
mysql> CALL delete_registro_tabla('12');
Query OK, 0 rows affected (0.06 sec)
 
mysql> SELECT * FROM tabla;
+--------+--------+--------+
| campo1 | campo2 | campo3 |
+--------+--------+--------+
|     10 |     12 |    120 |
|     13 |      1 |     13 |
+--------+--------+--------+
2 rows in set (0.00 sec)

Hasta aquí, funciona correctamente, eliminando el registro con campo1 = 12. Veamos ahora qué pasa si queremos hacer lo mismo que en tu caso:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
mysql> CALL delete_registro_tabla('12 or 1=1');
Query OK, 0 rows affected (0.00 sec)
 
mysql> SELECT * FROM tabla;
+--------+--------+--------+
| campo1 | campo2 | campo3 |
+--------+--------+--------+
|     10 |     12 |    120 |
|     13 |      1 |     13 |
+--------+--------+--------+
2 rows in set (0.00 sec)
 
mysql> CALL delete_registro_tabla('''12'' or 1=1');
Query OK, 0 rows affected (0.00 sec)
 
mysql> SELECT * FROM tabla;
+--------+--------+--------+
| campo1 | campo2 | campo3 |
+--------+--------+--------+
|     10 |     12 |    120 |
|     13 |      1 |     13 |
+--------+--------+--------+
2 rows in set (0.00 sec)

Observa que aquí no borra todos los registos, como en tu caso. Es decir, un simple cambio al usar USING puede prevenir un ataque de SQL Injection.

entonces, tal como dice cesar al final de su post:

1
Lo que debe enviar en los parametros, son valores, y validar/usar dichos valores dentro del SP.

Saludos
Leo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
2
Comentar
sin imagen de perfil
Val: 102
Bronce
Ha disminuido 1 puesto en MySQL (en relación al último mes)
Gráfica de MySQL

Error al Inserta un registro en mysql

Publicado por Miguel (60 intervenciones) el 26/06/2018 19:50:45
Hola Leonardo

Al final he montado todos los Insert, updated y deletes utilizando los nombres reales y ha sido la única forma de que todo me funcionen.

Quería preguntarte por este ejemplo que pusiste.

mysql> CREATE PROCEDURE delete_registro_tabla(
-> IN txtCampo VARCHAR(50)
-> )
-> BEGIN
-> SET @campo = txtCampo;
-> PREPARE stm FROM 'delete from tabla where campo1 = ?';
-> EXECUTE stm USING @campo;
-> DEALLOCATE PREPARE stm;
-> END$$

Imagino que la tabla es también un parámetro aunque aquí no aparece.

Podrías mirar una función que tengo del "Registro Máximo", pues se ejecuta y me saca el valor del último registro pero no se como cargarlo a una variable para luego incrementarlo tal y como hacía con Access.

Te adjunto una hoja donde tienes todo el código.

Gracias y un saludo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 953
Oro
Ha mantenido su posición en MySQL (en relación al último mes)
Gráfica de MySQL

Error al Inserta un registro en mysql

Publicado por leonardo_josue (414 intervenciones) el 26/06/2018 23:45:36
Hola de nuevo Miguel:

No es correcto que utilices un mismo post para hablar de problemas distintos. Cuando tengas una nueva duda, es mejor abrir un nuevo post, así todos los foristas podrán participar en la discusión y plantearte una respuesta... Si el tema tiene relación con otro post y te interesa que se tengan los detalles, simplemente incluyes una liga hacia los otros post's. Pero bueno, ojo para la próxima. Ahora volvamos a tu post,

1
Imagino que la tabla es también un parámetro aunque aquí no aparece.

No, en mi sentencia, mi tabla se llama así "tabla" por eso es que no se envía como parámetro así, cuando hago los SELECT de ejemplo pongo esto:

1
SELECT * FROM tabla;

es decir, a modo de ejemplo utilicé este nombre... como te comenté, la idea es que el nombre de la tabla no sea GENERICO, sino que cada SP haga referencia a una y solo a una tabla y nada más... en caso de recibir un ataque de inyección de código podrías "limitar" los daños sólo a esta tabla (aunque eso tampoco necesariamente sea siempre).

Ahora, con respecto a tu código, insisto en que estás abusando de las sentencias preparadas cuando no tienes necesidad de hacerlo.

1
2
3
4
5
6
7
CREATE DEFINER=`root`@`localhost` PROCEDURE `MaximoReg_Calle`(
)
BEGIN
prepare stm from 'Select max(idcalle) from Calles';
execute stm;
deallocate prepare stm;
END

Aquí ni siquiera tienes formas una consulta "dinámica", sino que es fija, entonces ¿para qué utilizas una sentencia preparada si puedes ejecutarla directamente? ahora, si necesitas regresar el valor que resulta de ejecutar la consulta tienes de dos sopas:

1. Utilizas FUNCIONES en lugar de Procedimientos almacenados:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
mysql> DROP FUNCTION IF EXISTS max_tabla;
Query OK, 0 rows affected (0.01 sec)
 
mysql> DELIMITER $$
mysql> CREATE FUNCTION fn_max_tabla() RETURNS int(11)
    -> BEGIN
    ->   DECLARE max_value INT(11);
    ->   SET max_value = 0;
    ->   SELECT MAX(id) INTO max_value FROM tabla;
    ->   RETURN max_value;
    -> END$$
Query OK, 0 rows affected (0.00 sec)
 
mysql> DELIMITER ;
mysql> SELECT * FROM tabla;
+----+-------------+
| id | descripcion |
+----+-------------+
|  1 | uno         |
|  2 | dos         |
|  3 | tres        |
+----+-------------+
3 rows in set (0.00 sec)
 
mysql> SELECT fn_max_tabla();
+-------------+
| max_tabla() |
+-------------+
|           3 |
+-------------+
1 row in set (0.00 sec)

2. Utilizando SP con un valor de salida:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
mysql> DROP PROCEDURE IF EXISTS sp_max_tabla;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> DELIMITER $$
mysql> CREATE PROCEDURE sp_max_tabla(OUT max_value int(11))
    -> BEGIN
    ->   SELECT max(id) INTO max_value FROM tabla;
    -> END$$
Query OK, 0 rows affected (0.00 sec)
mysql> DELIMITER ;
 
mysql> SET @max_valor = 0;
Query OK, 0 rows affected (0.00 sec)
 
mysql> call sp_max_tabla(@max_valor);
Query OK, 1 row affected (0.00 sec)
 
mysql> SELECT @max_valor;
+------------+
| @max_valor |
+------------+
|          3 |
+------------+
1 row in set (0.00 sec)

Dale un vistazo para ver si te sirve:

Saludos
Leo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar