Eliminar con Unirse en MySQL

501

Aquí está el script para crear mis tablas:

CREATE TABLE clients (
   client_i INT(11),
   PRIMARY KEY (client_id)
);
CREATE TABLE projects (
   project_id INT(11) UNSIGNED,
   client_id INT(11) UNSIGNED,
   PRIMARY KEY (project_id)
);
CREATE TABLE posts (
   post_id INT(11) UNSIGNED,
   project_id INT(11) UNSIGNED,
   PRIMARY KEY (post_id)
);

En mi código PHP, al eliminar un cliente, quiero eliminar todas las publicaciones de proyectos:

DELETE 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;

La tabla de publicaciones no tiene una clave foránea client_id, solo project_id. Quiero eliminar las publicaciones en proyectos que han pasado client_id.

Esto no funciona en este momento porque no se eliminan las publicaciones.

GeekJock
fuente
10
Creo que la respuesta de Yehosef debería ser la aceptada, ya que usa Join como usted pidió y funciona mejor que usar una cláusula IN como propuso yukondude ...
Gerardo Grignoli
2
El patrón preferido es un DELETE posts FROM posts JOIN projects ..., en lugar de un IN (subquery)patrón. (La respuesta de Yehosef da un ejemplo del patrón preferido.)
spencer7593
@GerardoGrignoli, ¿funciona mejor para un motor o una versión particular de MySQL? No hay ninguna razón por la cual las dos consultas tengan un rendimiento diferente, ya que AFAIK son idénticas. Por supuesto, si tuviera un centavo por cada vez que mi optimizador de consultas hiciera algo estúpido ...
Paul Draper
También puede usar aliaspara el nombre de la tabla y usar eso.
biniam

Respuestas:

1254

Solo necesita especificar que desea eliminar las entradas de la poststabla:

DELETE posts
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

EDITAR: para obtener más información, puede ver esta respuesta alternativa

Yehosef
fuente
117
Debe tenerse en cuenta que esta es la respuesta correcta porque la unión lo obliga a usar "BORRAR publicaciones DESDE publicaciones" en lugar de "BORRAR publicaciones normales", ya que la tabla para eliminar ya no es inequívoca. ¡Gracias!
siannopollo
8
Tenga en cuenta que no puede usar el método 'as' aquí, por ejemplo, proyectos de unión interna como p en p.project_id ...
zzapper
14
En realidad, puede usar un alias para tablas unidas, pero no para la tabla principal (publicaciones). "BORRAR publicaciones de publicaciones INNER JOIN projects p ON p.project_id = posts.project_id"
Weboide
85
"Si declaras un alias para una tabla, debes usar el alias cuando te refieras a la tabla" asíDELETE d FROM posts AS d JOIN projects AS p ON ...
KCD
14
esta es la mejor respuesta porque incluso puede eliminar de ambas tablas en una sola acciónDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium
84

Como está seleccionando varias tablas, la tabla para eliminar ya no es inequívoca. Necesitas seleccionar :

DELETE posts FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id

En este caso, table_name1y table_name2son la misma tabla, entonces esto funcionará:

DELETE projects FROM posts INNER JOIN [...]

Incluso puede eliminar de ambas tablas si desea:

DELETE posts, projects FROM posts INNER JOIN [...]

Tenga en cuenta que order byy limit no funciona para eliminaciones de varias tablas .

También tenga en cuenta que si declara un alias para una tabla, debe usar el alias al referirse a la tabla:

DELETE p FROM posts as p INNER JOIN [...]

Las contribuciones de Carpetsmoker y etc .

Pacerier
fuente
3
Si está respondiendo mejor, al menos podría hacer que el SQL sea más legible. Todas las demás referencias SQL en esta pregunta tienen palabras clave en mayúscula (excepto una con 0 votos). No estoy seguro de por qué revertiste mis ediciones.
Yehosef
3
@Yehosef, hay un grupo de personas que consideran que los CAPS son realmente deslumbrantes. Creo que no soy el único, también he visto a muchas personas en minúsculas.
Pacerier
1
bastante justo - Respeto tu derecho a escribir tu respuesta en el estilo que quieras;)
Yehosef
77
Para agregar a la discusión de mayúsculas / minúsculas, es cierto, puede usar el estilo que desee, pero en su respuesta, en realidad está mezclando estilos donde le parece conveniente: ONse escribe con mayúscula. Para los desarrolladores menos experimentados, puede transmitir que está bien ser desordenado e inconsistente en términos de estilo.
Sombra
16
Las palabras clave de mayúsculas no son deslumbrantes. ESTÁN HACIENDO LEÍDAS LAS CONSULTAS;)
Sachem el
50

O lo mismo, con una sintaxis ligeramente diferente (más amigable con la OMI):

DELETE FROM posts 
USING posts, projects 
WHERE projects.project_id = posts.project_id AND projects.client_id = :client_id;

Por cierto, con mysql el uso de combinaciones es casi siempre mucho más rápido que las subconsultas ...

ivanhoe
fuente
¿Qué significa el uso?
CMCDragonkai
1
Buena explicación de USING: stackoverflow.com/questions/11366006/mysql-on-vs-using
bigtex777
10
@ bigtex777: Tenga en cuenta que la palabra clave USING en las instrucciones SELECT tiene poco que ver con la misma palabra clave en una declaración DELETE. En SELECT especifica la lista de columnas para unir, mientras que en DELETEs es una lista de todas las tablas en una unión
ivanhoe
42

¡También puedes usar ALIAS como este, funciona, solo lo usé en mi base de datos! t es la tabla necesita eliminar de!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id
Propiedad España
fuente
1
esto es útil en combinaciones de teclas compuestas para evitar repetir los nombres de la tabla
Márquez
1
"En realidad, puede usar un alias para tablas unidas, pero no para la tabla principal (publicaciones). 'BORRAR publicaciones DE publicaciones INNER JOIN proyectos p ON p.project_id = posts.project_id'" - @ Weboide
Jeaf Gilbert
2
En realidad (citando dev.mysql.com/doc/refman/5.0/en/delete.html ) "Si declara un alias para una tabla, debe usar el alias cuando se refiera a la tabla: DELETE t1 FROM test AS t1, test2 WHERE ... "así que usar un alias está bien.
Peter Bowers
25

Estoy más acostumbrado a la solución de subconsulta para esto, pero no lo he probado en MySQL:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );
yukondude
fuente
85
Realmente debería evitar usar la palabra clave IN en SQL (aunque generalmente es más fácil de entender para los principiantes) y usar JOIN en su lugar (cuando sea posible), ya que las subconsultas generalmente hacen las cosas mucho más lentas.
usuario276648
14
Esto tiende a bloquear la base de datos cuando la subconsulta devuelve una gran cantidad de filas. También es inmensamente lento.
Raj
2
@yukondude De hecho, "IN" es mucho más fácil de entender que "JOIN" en 1st, y es por eso que las personas que no están realmente familiarizadas con SQL terminarán escribiendo "IN" en todas partes, mientras que podrían usar "JOIN" que funciona mejor ( o mucho mejor, dependiendo de la consulta). Recuerdo que hace varios años, casi todas mis consultas SQL serían reescritas por alguien que realmente sabía cómo escribir buenas consultas. Es por eso que agregué el comentario para evitar "IN", para que las personas sepan que si es posible, deben evitar usarlo.
user276648
10
La razón por la que vine a esta página es porque la consulta que escribí con una declaración IN fue lenta. Definitivamente evite la respuesta aceptada aquí.
MikeKulls
44
Tan antigua como es esta pregunta, es importante saber POR QUÉ debe usar JOIN en lugar de IN. Cuando esa condición se ejecuta en una fila, va a ejecutar esa consulta dentro de IN. Eso significa que si hay 100 filas que deben verificarse en DONDE, esa subconsulta se ejecutará 100 veces. Mientras que un JOIN solo se ejecutará UNA VEZ. Entonces, a medida que su base de datos se hace más y más grande, esa consulta tomará más y más tiempo para finalizar. @markus solo porque algo no sea crítico no significa que debas escribir un código incorrecto. Escribirlo un poco mejor le ahorrará mucho tiempo y dolor de cabeza en el futuro. :)
RisingSun
11

MySQL DELETE registros con JOIN

Generalmente usa INNER JOIN en la instrucción SELECT para seleccionar registros de una tabla que tenga registros correspondientes en otras tablas. También podemos usar la cláusula INNER JOIN con la declaración DELETE para eliminar registros de una tabla y también los registros correspondientes en otras tablas, por ejemplo, para eliminar registros de tablas T1 y T2 que cumplan una condición particular, use la siguiente declaración:

DELETE T1, T2
FROM T1
INNER JOIN T2 ON T1.key = T2.key
WHERE condition

Observe que coloca los nombres de tabla T1 y T2 entre DELETE y FROM. Si omite la tabla T1, la instrucción DELETE solo elimina registros en la tabla T2, y si omite la tabla T2, solo se eliminan los registros en la tabla T1.

La condición de unión T1.key = T2.key especifica los registros correspondientes en la tabla T2 que deben eliminarse.

La condición en la cláusula WHERE especifica qué registros en T1 y T2 deben eliminarse.

Aman Garg
fuente
11

Eliminar tabla individual:

Para eliminar entradas de la poststabla:

DELETE ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Para eliminar entradas de la projectstabla:

DELETE pj 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Para eliminar entradas de la clientstabla:

DELETE C
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id;

Eliminar varias tablas:

Para eliminar entradas de varias tablas de los resultados combinados, debe especificar los nombres de las tablas DELETEcomo una lista separada por comas:

Suponga que desea borrar las entradas de todas las tres tablas ( posts, projects, clients) para un cliente en particular:

DELETE C,pj,ps 
FROM clients C 
INNER JOIN projects pj ON C.client_id = pj.client_id
INNER JOIN posts ps ON pj.project_id = ps.project_id
WHERE C.client_id = :client_id
1000111
fuente
7

Intenta como a continuación:

DELETE posts.*,projects.* 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;
Sangeetha Narayana Moorthy
fuente
4

Otro método para eliminar usando una sub selección que es mejor que usar INseríaWHERE EXISTS

DELETE  FROM posts
WHERE   EXISTS ( SELECT  1 
                 FROM    projects
                 WHERE   projects.client_id = posts.client_id);

Una razón para usar esto en lugar de la combinación es que a DELETEcon JOINprohíbe el uso de LIMIT. Si desea eliminar en bloques para no producir bloqueos de tabla completos, puede agregar LIMITeste DELETE WHERE EXISTSmétodo.

Jim Clouse
fuente
1
¿Se puede escribir esta consulta con "alias"? La sintaxis no deja muy claro cómo postsdentro de EXISTS () es el mismo del postsque se eliminan las filas. (En mi humilde opinión de todos modos)
MattBianco
Te escucho, pero los alias no están permitidos en la tabla para eliminar. Las "publicaciones" en la subconsulta deben ser el nombre completo de la tabla, lo que significa que si desea reutilizar esa tabla en su subselección de la cláusula From, debe alias allí.
Jim Clouse
1
Esto funciona:DELETE p FROM posts p WHERE EXISTS ( SELECT 1 FROM projects WHERE projects.client_id = p.client_id);
MattBianco
4
mysql> INSERT INTO tb1 VALUES(1,1),(2,2),(3,3),(6,60),(7,70),(8,80);

mysql> INSERT INTO tb2 VALUES(1,1),(2,2),(3,3),(4,40),(5,50),(9,90);

BORRAR registros de una tabla:

mysql> DELETE tb1 FROM tb1,tb2 WHERE tb1.id= tb2.id;

BORRAR REGISTROS DE ambas tablas:

mysql> DELETE tb2,tb1 FROM tb2 JOIN tb1 USING(id);
zloctb
fuente
1

Si unirse no funciona para usted, puede probar esta solución. Es para eliminar registros huérfanos de t1 cuando no se usan claves foráneas + condiciones específicas de where. Es decir, elimina registros de la tabla1, que tienen el campo "código" vacío y que no tienen registros en la tabla2, que coinciden con el campo "nombre".

delete table1 from table1 t1 
    where  t1.code = '' 
    and 0=(select count(t2.name) from table2 t2 where t2.name=t1.name);
Kristjan Adojaan
fuente
0

Prueba esto,

DELETE posts.*
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id
Silambarasan
fuente
-3

- Tenga en cuenta que no puede usar un alias sobre la tabla donde necesita eliminar

DELETE tbl_pagos_activos_usuario
FROM tbl_pagos_activos_usuario, tbl_usuarios b, tbl_facturas c
Where tbl_pagos_activos_usuario.usuario=b.cedula
and tbl_pagos_activos_usuario.cod=c.cod
and tbl_pagos_activos_usuario.rif=c.identificador
and tbl_pagos_activos_usuario.usuario=c.pay_for
and tbl_pagos_activos_usuario.nconfppto=c.nconfppto
and NOT ISNULL(tbl_pagos_activos_usuario.nconfppto)
and c.estatus=50
Hernan Torres
fuente