SQL Error (1093): You can’t specify target table for update

SQL Error (1093): You can’t specify target table ‘menus_items’ for update in FROM clause

But why? Si estoy haciendo un insert!!

Os voy a comentar el motivo de mi sorpresa al encontrar el error y su preciosa solución.

Tengo una tabla con los diferentes campos  del menus, en “menus_items”. La tabla tiene una clave primaria menu_item_id que es AUTO_INCREMENT (por lo tanto está omitida en el insert).

La tabla tiene los siguientes campos:

menu_item_id,

menu_id,

parent_menu_item_id,

`code`,

`name`

Quiero que cuando inserte una secuencia en la tabla, parent_menu_item_id sea el identificador menu_item_id resultado de una búsqueda en la misma tabla por código.
Es decir, resultado de la query:

(select menu_item_id from menus_items where code='core-system' limit 1)

Así que ejecuto mi insert molón:

INSERT INTO
`menus_items`
(
<p dir="ltr">menu_id,</p>
<p dir="ltr">parent_menu_item_id,</p>
<p dir="ltr">`code`,</p>
<p dir="ltr">`name`</p>
)
VALUES
(
<p dir="ltr">1,</p>
<p dir="ltr">(select menu_item_id from menus_items where code='core-system' limit 1), 'system-auth-users',</p>
<p dir="ltr">'Usuarios'</p>
)
);

ERROR!!

SQL Error (1093): You can’t specify target table ‘menus_items’ for update in FROM clause

Efectivamente, estoy buscando sobre  una tabla en la cual estoy modificando. Si quisiera hacer una subquery a otra tabla no hay problema. Por ejemplo:

INSERT INTO
`menus_items`
(
<p dir="ltr">parent_menu_item_id,</p>
<p dir="ltr">`code`,</p>
<p dir="ltr">`name`</p>
)
VALUES
(
<p dir="ltr">(select menu_id from menus where code='BACKEND'),</p>
<p dir="ltr">'system-auth-users',</p>
<p dir="ltr">'Usuarios'</p>
)
);

Pero al ser la misma tabla MySQL no lo permite.

¿Entonces?

Bien, como solución podemos hace uso de variables:

select @MENU_ITEM_ID:=menu_item_id from menus_items where code='core-system' LIMIT 1;

Y ahora haciendo uso de la variable:

INSERT INTO
`menus_items`
(
parent_menu_item_id,
 `code`,
`name`
)
VALUES
(
@MENU_ITEM_ID,
'system-auth-users',
'Usuarios'
);

OHHHH

Me encanta :))

Si es necesario más información, si no queda claro, o si no es lo que estabais buscando. Comentarlo para que pueda mejorarlo 😉

Un saludo!


Anuncio publicitario

Cómo activar y visualizar el log de MySQL

En ocasiones no sabemos lo que MySQL hace por debajo. No sabemos si ha llegado a lanzarse la consulta  o qué error está dando porque no estamos capturando la excepción en la aplicación que estamos desarrollando.

La alternativa: activar y visualizar el log de MySQL.

Escribe las siguientes secuencias entrando en mysql desde consola.

Primero entra en mysql:

mysql -p

Luego activa la tabla de log de mysql:

set global general_log=ON

Pasos básicos: veamos la tabla general_log:

mysql> describe mysql.general_log;
+--------------+------------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+-------------------+-----------------------------+
| event_time | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| user_host | mediumtext | NO | | NULL | |
| thread_id | int(11) | NO | | NULL | |
| server_id | int(10) unsigned | NO | | NULL | |
| command_type | varchar(64) | NO | | NULL | |
| argument | mediumtext | NO | | NULL | |
+--------------+------------------+------+-----+-------------------+-----------------------------+
6 rows in set (0.07 sec)

Así que esta tabla la puedes utilizar como una tabla común del esquema «mysql». Ejemplos:

Si deseamos encontrar las últimas llamadas a mysql. 

select * from mysql.general_log order by event_time desc limit 5;

Si deseamos buscar por una IP concreto que ha lanzado la llamada a esa base de datos:


select * from mysql.general_log where user_host like '%192.168.%' order by event_time desc limit 5;

OJO! Esta tabla crece y crece sin parar. Es recomendable desactivarla


set global general_log=OFF

y de vez en cuando limpiarla:


truncate table mysql.general_log;

Toda ayuda para ver los errores es poca! Espero os sea de utilidad

Agradecimientos a @rcasas

Multi update MySQL

Aquí hay una solución a “Multi update mysql” sin romperse mucho la cabeza y sin programar.

Imaginemos que tenemos una tabla ‘grabaciones’ que tiene los campos ‘fecha_grabacion’ y ‘fecha_creacion’ y queremos hacer un update por cada grabacion de forma que la fecha de grabación pase a ser la fecha de creación.

Es hacer por cada fila:

update grabaciones set fecha_grabacion=’fecha de creacion de la grabacion id 1835’’ where grabacion_id=1835;

En esta imagen vemos en la pestaña “grabaciones” sus contenidos.

tabla_contenidos

Hacemos una query que con ‘CONCAT’ creemos el ‘UPDATE’ a partir de la query de las filas que queremos modificar:

select concat(‘update grabaciones set fecha_grabacion=\»,fecha_creacion,’\’ where grabacion_id=’,grabacion_id) from grabaciones where fecha_grabacion = ‘0000-00-00 00:00:00’;

Eso nos devuelve una única columna con updates. Como se muestra en la figura.

resultados mostrados en la query

La exportamos como texto, y ya tenemos nuestros comandos updates para aplicarlos.

update grabaciones set fecha_grabacion=’2012-10-08 09:55:44′ where grabacion_id=1775;
update grabaciones set fecha_grabacion=’2012-10-08 09:55:48′ where grabacion_id=1831;
update grabaciones set fecha_grabacion=’2012-10-08 09:55:48′ where grabacion_id=1835;
update grabaciones set fecha_grabacion=’2012-10-08 09:56:17′ where grabacion_id=2228;
update grabaciones set fecha_grabacion=’2012-10-08 09:56:43′ where grabacion_id=2573;
update grabaciones set fecha_grabacion=’2012-10-08 09:56:52′ where grabacion_id=2693;
update grabaciones set fecha_grabacion=’2012-10-08 09:57:00′ where grabacion_id=2806;
update grabaciones set fecha_grabacion=’2012-10-08 09:57:14′ where grabacion_id=3000;
update grabaciones set fecha_grabacion=’2012-10-08 09:57:20′ where grabacion_id=3081;
update grabaciones set fecha_grabacion=’2012-10-08 09:57:25′ where grabacion_id=3149;
update grabaciones set fecha_grabacion=’2012-10-10 19:30:46′ where grabacion_id=3326;

….

Ya está!

Para un resultado de más de 1000 updates, esta forma tardará mucho en ejecutarse, así que es mejor otras alternativas.

Comentar mejores opciones!! y si te parece interesante… compartir es vivir!

Gracias!

Can’t create table (errno: 150)

Este error es tan típico, que una vez que se ya has sufrido estos fallos, se intentan evitar teniendo un poco de cuidado al crear las tablas. Muchos ya lo conocéis y hay mil páginas…. pero he querido completarlo con algún detalle! Ahí van!

  1. Opción:  Estás añadiendo una clave foránea cuyo tipo no coincide al tipo que hace referencia.

OJO! con INT(11) VS INT(10) : algunas herramientas que hacen de interfaz de bases de datos crean PRIMARY_KEY como INT(11) y el resto de campos de tipo numérico como INT(10).

OJO! con UNSIGNED. Si recibes código heredado y te estás volviendo loco puede que esté indicado como UNSIGNED.

OJO! que la clave foránea sea pueda ser NULL, no influye. Ejemplo:

`modified_by` INT(11) NULL DEFAULT NULL.

 

  1. Opción: Estás añadiendo una clave foránea y el campo al que estás haciendo referencia no existe con ese valor.

Es decir. Imaginemos que a la clave ‘modified_by’ lo tienes inicializado a 5. Te has dado cuenta que has añadido el campo, pero no has añadido la propiedad de que es una foreing key a la tabla de usuarios! Si luego al poner que modified_by es fk te sale este error, comprueba que el usuario 5 existe en la tabla de usuarios.

OJO! Cuando modifiques una tabla con un campo existente ‘modified_by’ que es nulo y pongas que la foreing key no puede ser nulo. Ejemplo:

`modified_by` INT(11) NOT NULL.

No te va a dejar modificar la tabla a no ser de que le pongas un valor inicializado y que sea correcto. Tendrás que actualizar el campo modified_by por un valor correcto y luego crear la tabla. (el mismo caso que antes, pero ahora con NULL).

 

  1. Opción: Si pones “On Delete Set Null” pero el campo está definido como NOT NULL.

OJO! Te contradices más que el programa electoral de Rajoy!

 

Cuándo utilizar el tipo de dato ENUM en bases de datos MySQL

Hasta hace poco. No acostumbraba a utilizar el campo ENUM como tipo de dato en una tabla.

La duda que planeo queda clara en el siguiente ejemplo:

//SIN ENUM


create table 'usuarios'(
          usuario_id INT,
          nombre VARCHAR(100),
          usuario_tipo_id INT
        ) TYPE=innodb;</code>
)

(Siendo usuario_tipo_id una fk a usuario_tipo_id de la tabla inferior).


create table 'usuarios_tipos'(

usuario_tipo_id INT,

descripcion VARCHAR(200)

)

ó


// CON ENUM

create table 'usuarios'(

          usuario_id INT,
          nombre VARCHAR(100),
          tipo ENUM 
        ) TYPE=innodb;</code>
)

¿Cuándo tomar una decisión u otra?

Decisión 1:

  1. El tipo de usuarios es gestionado desde la aplicación.
  2. El tipo de usuarios puede crecer o es incierto
  3. Cuando existe un gran número de tipo de usuarios.
  4. El dato lo muestro por pantalla y es sensible a que el sitio cambie de idioma.

Decisión 2:

  1. Existe un número limitado de tipos de usuario y siempre es el mismo.
  2. Nuestra base de datos ya es suficientemente grande y se nos está complicando bastante.
  3. Cuando no voy a filtrar por ese tipo (por ejemplo porque los voy a mostrar en ventanas diferentes y con una gestión independiente).
  4. Si queremos utilizarlo a estilo booleano, para que no nos olvidemos cual es el verdadero o cuál es el falso (ejemplo:  active ENUM (‘no_active’,’active’)

Error en ejecución MySQL

Cuando estamos desesperados, cuando sabemos que algo oscuro está haciendo MySQL, cuando sospechamos que hay algunas tablas bloqueadas o algún error de memoria en MySQL, en estos casos, aconsejo leer el log de MySQL.

Para ello hace falta ir al servidor donde tenemos instalado mysql.

Entrar en la misma consola de Mysql mediante:

mysql -p

Y activar el log.

set global general_log=ON

desc mysql.general_log;

Para desactivarlo hace falta poner

set global general_log=OFF

En mi caso me fue de gran utilidad!! suerte!!