Error 1093 de MySQL: no se puede especificar la tabla de destino para la actualización en la cláusula FROM

StackOverflow https://stackoverflow.com/questions/45494

Pregunta

tengo una mesa story_category en mi base de datos con entradas corruptas.La siguiente consulta devuelve las entradas corruptas:

SELECT * 
FROM  story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
       story_category ON category_id=category.id);

Intenté borrarlos ejecutando:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category 
      INNER JOIN story_category ON category_id=category.id);

Pero me sale el siguiente error:

#1093 - No se puede especificar la tabla de destino 'story_category' para actualizar en la cláusula FROM

¿Cómo puedo superar esto?

¿Fue útil?

Solución

Actualizar:Esta respuesta cubre la clasificación general de errores.Para obtener una respuesta más específica sobre cómo manejar mejor la consulta exacta del OP, consulte otras respuestas a esta pregunta.

En MySQL, no puedes modificar la misma tabla que usas en la parte SELECT.
Este comportamiento está documentado en:http://dev.mysql.com/doc/refman/5.6/en/update.html

Tal vez puedas unir la mesa a sí misma.

Si la lógica es lo suficientemente simple como para remodelar la consulta, pierda la subconsulta y una la tabla a sí misma, empleando criterios de selección adecuados.Esto hará que MySQL vea la tabla como dos cosas diferentes, permitiendo que se realicen cambios destructivos.

UPDATE tbl AS a
INNER JOIN tbl AS b ON ....
SET a.col = b.col

Alternativamente, intente anidar la subconsulta más profundamente en una cláusula from...

Si absolutamente necesita la subconsulta, hay una solución, pero es feo por varias razones, incluido el rendimiento:

UPDATE tbl SET col = (
  SELECT ... FROM (SELECT.... FROM) AS x);

La subconsulta anidada en la cláusula FROM crea una tabla temporal implícita, por lo que no cuenta como la misma tabla que estás actualizando.

...pero cuidado con el optimizador de consultas

Sin embargo, tenga en cuenta que desde MySQL 5.7.6 y en adelante, el optimizador puede optimizar la subconsulta y aún así mostrarle el error.Por suerte, el optimizer_switch La variable se puede utilizar para desactivar este comportamiento;aunque no podría recomendar hacer esto más que como una solución a corto plazo o para pequeñas tareas puntuales.

SET optimizer_switch = 'derived_merge=off';

Gracias a Pedro V.Mørch por este consejo en los comentarios.

La técnica de ejemplo fue del barón Schwartz, publicado originalmente en Nabble, parafraseado y ampliado aquí.

Otros consejos

nexorex proporcionó un muy buena solucion para eliminar con combinación de la misma tabla.

Si haces esto:

DELETE FROM story_category
WHERE category_id NOT IN (
        SELECT DISTINCT category.id AS cid FROM category 
        INNER JOIN story_category ON category_id=category.id
)

obtendrás un error.

Pero si envuelve la condición en una selección más:

DELETE FROM story_category
WHERE category_id NOT IN (
    SELECT cid FROM (
        SELECT DISTINCT category.id AS cid FROM category 
        INNER JOIN story_category ON category_id=category.id
    ) AS c
)

haría lo correcto!!

Explicación: El optimizador de consultas hace un optimización de fusión derivada para la primera consulta (lo que hace que falle con el error), pero la segunda consulta no califica para el optimización de fusión derivada.Por lo tanto, el optimizador se ve obligado a ejecutar la subconsulta primero.

El inner join en su subconsulta es innecesario.Parece que deseas eliminar las entradas en story_category donde el category_id no esta en el category mesa.

Hacer esto:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category);

En lugar de eso:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN
         story_category ON category_id=category.id);

Recientemente tuve que actualizar registros en la misma tabla. Lo hice como se muestra a continuación:

UPDATE skills AS s, (SELECT id  FROM skills WHERE type = 'Programming') AS p
SET s.type = 'Development' 
WHERE s.id = p.id;
DELETE FROM story_category
WHERE category_id NOT IN (
    SELECT cid FROM (
        SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id
    ) AS c
)

Si no puedes hacer

UPDATE table SET a=value WHERE x IN
    (SELECT x FROM table WHERE condition);

como es la misma tabla, puedes engañar y hacer:

UPDATE table SET a=value WHERE x IN
    (SELECT * FROM (SELECT x FROM table WHERE condition) as t)

[actualizar o eliminar o lo que sea]

Esto es lo que hice para actualizar el valor de una columna Prioridad en 1 si es >=1 en una tabla y en su cláusula WHERE usando una subconsulta en la misma tabla para asegurarme de que al menos una fila contenga Prioridad=1 (porque esa era la condición que se debe verificar al realizar la actualización):


UPDATE My_Table
SET Priority=Priority + 1
WHERE Priority >= 1
AND (SELECT TRUE FROM (SELECT * FROM My_Table WHERE Priority=1 LIMIT 1) as t);

Sé que es un poco feo pero funciona bien.

Puede insertar los identificadores de las filas deseadas en una tabla temporal y luego eliminar todas las filas que se encuentran en esa tabla.

que puede ser lo que quiso decir @Cheekysoft al hacerlo en dos pasos.

De acuerdo a la sintaxis de actualización de Mysql vinculado por @CheekySoft, dice justo en la parte inferior.

Actualmente, no se puede actualizar una tabla y seleccionar de la misma tabla en una subconsulta.

Supongo que estás eliminando de store_category mientras aún lo seleccionas en la unión.

Si algo no funciona, al pasar por la puerta principal, tome la puerta trasera:

drop table if exists apples;
create table if not exists apples(variety char(10) primary key, price int);

insert into apples values('fuji', 5), ('gala', 6);

drop table if exists apples_new;
create table if not exists apples_new like apples;
insert into apples_new select * from apples;

update apples_new
    set price = (select price from apples where variety = 'gala')
    where variety = 'fuji';
rename table apples to apples_orig;
rename table apples_new to apples;
drop table apples_orig;

Es rápido.Cuanto más grandes sean los datos, mejor.

La forma más sencilla de hacer esto es utilizar un alias de tabla cuando haga referencia a la tabla de consulta principal dentro de la subconsulta.

Ejemplo :

insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab));

Cámbielo a:

insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P));

prueba esto

DELETE FROM story_category 
WHERE category_id NOT IN (
SELECT DISTINCT category.id 
FROM (SELECT * FROM STORY_CATEGORY) sc;

Intente guardar el resultado de la instrucción Select en una variable separada y luego utilícelo para eliminar la consulta.

¿Qué tal esta consulta? Espero que te ayude.

DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top