Tengo una tabla 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);
Traté de eliminarlos 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?
mysql
subquery
sql-delete
mysql-error-1093
Sergio del Amo
fuente
fuente
Respuestas:
Actualización: esta respuesta cubre la clasificación de error general. 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 puede modificar la misma tabla que usa en la parte SELECT.
Este comportamiento está documentado en: http://dev.mysql.com/doc/refman/5.6/en/update.html
Quizás puedas unirte a la mesa
Si la lógica es lo suficientemente simple como para cambiar la forma de la consulta, pierda la subconsulta y una la tabla a sí misma, empleando los criterios de selección adecuados. Esto hará que MySQL vea la tabla como dos cosas diferentes, permitiendo que se produzcan cambios destructivos.
Alternativamente, intente anidar la subconsulta más profundamente en una cláusula from ...
Si realmente necesita la subconsulta, hay una solución alternativa, pero es fea por varias razones, incluido el rendimiento:
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á actualizando.
... pero ten cuidado con el optimizador de consultas
Sin embargo, tenga en cuenta que desde MySQL 5.7.6 y posteriores, el optimizador puede optimizar la subconsulta y aún así le dará el error. Afortunadamente, la
optimizer_switch
variable se puede usar para desactivar este comportamiento; aunque no podría recomendar hacer esto como algo más que una solución a corto plazo, o para pequeñas tareas puntuales.Gracias a Peter V. Mørch por este consejo en los comentarios.
La técnica de ejemplo fue del barón Schwartz, originalmente publicado en Nabble , parafraseado y extendido aquí.
fuente
SET optimizer_switch = 'derived_merge=off';
:-(NexusRex proporcionó una muy buena solución para eliminar con join de la misma tabla.
Si haces esto:
vas a obtener un error
Pero si envuelve la condición en una selección más:
¡Haría lo correcto!
Explicación: El optimizador de consultas realiza una 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 la optimización de fusión derivada . Por lo tanto, el optimizador se ve obligado a ejecutar la subconsulta primero.
fuente
El
inner join
en su subconsulta es innecesario. Parece que desea eliminar las entradas enstory_category
dondecategory_id
no está en lacategory
tabla.Hacer esto:
En lugar de eso:
fuente
DISTINCT
es innecesario aquí, para un mejor rendimiento;).where in
en la columna ID, por lo que no necesita consultar la tabla primaria.Recientemente tuve que actualizar registros en la misma tabla que hice a continuación:
fuente
UPDATE skills SET type='Development' WHERE type='Programming';
? Esto no parece estar respondiendo la pregunta original.UPDATE skills SET type='Development' WHERE type='Programming';
. No entiendo por qué tanta gente no está pensando en lo que hacen ...fuente
UPDATE tbl AS a INNER JOIN tbl AS b ON .... SET a.col = b.col
: esto funcionaría como un alias diferente para la misma tabla que se usa aquí. De manera similar, en la respuesta de @ NexusRex, la primeraSELECT
consulta actúa como una tabla derivada en la questory_category
se usa por segunda vez. Entonces, el error mencionado en el OP no debería tener lugar aquí, ¿verdad?Si no puedes hacer
porque es la misma tabla, puedes engañar y hacer:
[actualizar o eliminar o lo que sea]
fuente
Esto es lo que hice para actualizar un valor de columna de Prioridad en 1 si es> = 1 en una tabla y en su cláusula WHERE utilizando una subconsulta en la misma tabla para asegurarse de que al menos una fila contenga Prioridad = 1 (porque esa fue la condición a comprobar mientras se realiza la actualización):
Sé que es un poco feo, pero funciona bien.
fuente
La forma más sencilla de hacer esto es usar un alias de tabla cuando se refiere a una tabla de consulta principal dentro de la subconsulta.
Ejemplo:
Cámbielo a:
fuente
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 @Cheekysoft quiso decir al hacerlo en dos pasos.
fuente
De acuerdo con la sintaxis de ACTUALIZACIÓN de Mysql vinculada por @CheekySoft, dice justo en la parte inferior.
Supongo que está eliminando de store_category mientras sigue seleccionando en la unión.
fuente
Para la consulta específica que el OP está tratando de lograr, la forma ideal y más eficiente de hacer esto NO es utilizar una subconsulta.
Estas son las
LEFT JOIN
versiones de las dos consultas del OP:Nota:
DELETE s
restringe las operaciones de eliminación a lastory_category
tabla.Documentación
fuente
UPDATE
declaraciones y subconsultas unidas. Permitiéndole rendirLEFT JOIN ( SELECT ... )
en lugar de hacerloWHERE IN( SELECT ... )
, haciendo que la implementación sea útil en muchos casos de uso.Si algo no funciona, al pasar por la puerta principal, tome la puerta trasera:
Es rápido. Cuanto más grandes sean los datos, mejor.
fuente
Intente guardar el resultado de la instrucción Select en una variable separada y luego utilícelo para eliminar la consulta.
fuente
prueba esto
fuente
¿qué tal esta consulta espero que ayude
fuente
DELETE story_category FROM ...
sin embargo, la subconsulta unida no es necesaria en este contexto y se puede realizar utilizandoLEFT JOIN category AS cat ON cat.id = story_category.category_id WHERE cat.id IS NULL
, tenga en cuenta que los criterios de unión en la respuesta hacen referencia incorrectamentestory_category.id = cat.id
En lo que respecta a las preocupaciones, desea eliminar filas
story_category
que no existen encategory
.Aquí está su consulta original para identificar las filas a eliminar:
La combinación
NOT IN
con una subconsulta queJOIN
es la tabla original parece complicada de manera innecesaria. Esto se puede expresar de una manera más directa connot exists
una subconsulta correlacionada:Ahora es fácil convertir esto en una
delete
declaración:Este quer se ejecutaría en cualquier versión de MySQL, así como en la mayoría de las otras bases de datos que conozco.
Demostración en DB Fiddle :
fuente