Usuń z Dołącz w MySQL

501

Oto skrypt do tworzenia moich tabel:

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)
);

W moim kodzie PHP, usuwając klienta, chcę usunąć wszystkie posty projektów:

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

Tabela stanowisk nie ma klucza obcego client_id, tylko project_id. Chcę usunąć posty w projektach, które przeszły client_id.

To nie działa teraz, ponieważ żadne posty nie są usuwane.

GeekJock
źródło
10
Myślę, że odpowiedź Yehosefa powinna być zaakceptowana, ponieważ używa Join, jak prosiłeś, i że działa lepiej niż przy użyciu klauzuli IN, jak zaproponował yukondude ...
Gerardo Grignoli
2
Preferowanym wzorem jest DELETE posts FROM posts JOIN projects ...raczej niż IN (subquery)wzór. (Odpowiedź Yehosefa podaje przykład preferowanego wzoru.)
spencer7593
@GerardoGrignoli, działa lepiej dla określonego silnika lub wersji MySQL? Nie ma powodu, dla którego te dwa zapytania powinny działać inaczej, ponieważ AFAIK są identyczne. Oczywiście, gdybym miał nikiel za każdym razem, mój optymalizator zapytań zrobił coś głupiego ...
Paul Draper
Możesz także użyć aliasnazwy tabeli i użyć jej.
biniam

Odpowiedzi:

1253

Musisz tylko określić, że chcesz usunąć wpisy z poststabeli:

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

EDYCJA: Aby uzyskać więcej informacji, możesz zobaczyć tę alternatywną odpowiedź

Yehosef
źródło
117
Należy zauważyć, że jest to poprawna odpowiedź, ponieważ łączenie zmusza cię do użycia „USUŃ posty z postów” zamiast zwykłego „USUŃ posty”, ponieważ tabela do usunięcia nie jest już jednoznaczna. Dzięki!
siannopollo
8
Zauważ, że nie możesz tutaj użyć metody „as”, np. Projekty łączenia wewnętrznego jak p na p.project_id ...
zzapper
14
Właściwie możesz użyć aliasu dla połączonych tabel, ale nie dla głównej tabeli (postów). „USUŃ posty Z postów INNER JOIN projekty p ON p.project_id = posts.project_id”
Weboide
85
„Jeśli deklarujesz alias dla tabeli, musisz używać aliasu w odniesieniu do tabeli” w ten sposóbDELETE d FROM posts AS d JOIN projects AS p ON ...
KCD
14
to najlepsza odpowiedź, ponieważ możesz nawet usunąć z obu tabel w jednym działaniuDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium
84

Ponieważ wybierasz wiele tabel, tabela, z której chcesz usunąć, nie jest już jednoznaczna. Musisz wybrać :

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

W takim przypadku table_name1i table_name2są w tej samej tabeli, więc to zadziała:

DELETE projects FROM posts INNER JOIN [...]

Możesz nawet usunąć z obu tabel, jeśli chcesz:

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

Uwaga: order byi limit nie działa w przypadku usuwania wielu tabel .

Pamiętaj również, że jeśli deklarujesz alias dla tabeli, musisz użyć aliasu w odniesieniu do tabeli:

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

Wkłady Carpetsmoker itp .

Pacerier
źródło
3
Jeśli robisz lepszą odpowiedź - przynajmniej możesz sprawić, że SQL będzie bardziej czytelny. Wszystkie pozostałe odwołania SQL w tym pytaniu zawierają słowa kluczowe pisane wielkimi literami (z wyjątkiem jednego z 0 głosami). Nie jestem pewien, dlaczego cofnąłeś moje zmiany.
Yehosef,
3
@ Yehosef, Istnieje grupa ludzi, dla których CAPS jest naprawdę rażący. Wierzę, że nie jestem jedyny, widziałem też sporo osób, które idą w stylu małych liter.
Pacerier
1
sprawiedliwie - szanuję twoje prawo do napisania odpowiedzi w stylu, który lubisz;)
Yehosef
7
Aby dodać do dyskusji na temat ONwielkich / małych liter , to prawda, możesz użyć dowolnego stylu, który ci się podoba, ale w swojej odpowiedzi tak naprawdę miksujesz style, które uważasz za wygodne - to jest wielkie. Mniej doświadczonym programistom może powiedzieć, że jest okropny i niespójny pod względem stylu.
Odcień
16
SŁOWA KLUCZOWE NIE są rażące. UCZYNIAJĄ PYTANIA;)
Sachem,
50

Lub to samo, z nieco inną składnią (bardziej przyjazną dla IMO):

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

BTW, z mysql za pomocą złączeń jest prawie zawsze znacznie szybszy niż podzapytania ...

ivanhoe
źródło
Co oznacza USING?
CMCDragonkai
1
Dobre wyjaśnienie USING: stackoverflow.com/questions/11366006/mysql-on-vs-using
bigtex777
10
@ bigtex777: Pamiętaj, że słowo kluczowe USING w instrukcjach SELECT ma niewiele wspólnego z tym samym słowem kluczowym w instrukcji DELETE. W SELECTs określa listę kolumn do przyłączenia, podczas gdy w DELETE jest to lista wszystkich tabel w złączeniu
ivanhoe 16.04.15
42

Możesz także użyć ALIAS w ten sposób, to działa właśnie użyłem go w mojej bazie danych! t oznacza, że ​​tabela wymaga usunięcia!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id
Nieruchomość Hiszpania
źródło
1
przydaje się to w połączeniach z kluczem złożonym, aby uniknąć powtarzania nazw tabel
Marquez
1
„Właściwie możesz użyć aliasu dla połączonych tabel, ale nie dla głównej tabeli (postów). 'USUŃ posty Z postów WEWNĘTRZNE DOŁĄCZ projekty p ON p.project_id = posts.project_id'” - @ Weboide
Jeaf Gilbert
2
Właściwie (cytowanie z dev.mysql.com/doc/refman/5.0/en/delete.html ) „Jeśli deklarujesz alias dla tabeli, musisz użyć aliasu w odniesieniu do tabeli: USUŃ t1 Z testu AS t1, test2 WHERE ... ”, więc użycie aliasu jest w porządku.
Peter Bowers
25

Jestem bardziej przyzwyczajony do rozwiązania tego podzapytania, ale nie wypróbowałem tego w MySQL:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );
yukondude
źródło
85
Naprawdę powinieneś unikać używania słowa kluczowego IN w SQL (chociaż zwykle jest to łatwiejsze do zrozumienia dla początkujących) i zamiast tego używaj ŁĄCZENIA (jeśli to możliwe), ponieważ podkwerendy zwykle spowalniają pracę.
user276648,
14
Powoduje to awarię DB, gdy kwerenda podrzędna zwraca ogromną liczbę wierszy. Jest również niezwykle powolny.
Raj
2
@yukondude Rzeczywiście, „IN” jest o wiele łatwiejsze do zrozumienia niż „DOŁĄCZ” na 1, i dlatego ludzie, którzy tak naprawdę nie znają SQL, będą wszędzie pisać „IN”, podczas gdy mogliby używać „JOIN”, który działa lepiej ( lub o wiele więcej, w zależności od zapytania). Pamiętam kilka lat temu, że prawie wszystkie moje zapytania SQL zostałyby przepisane przez kogoś, kto faktycznie wiedział, jak pisać dobre zapytania. Dlatego dodałem komentarz, aby uniknąć „IN”, aby ludzie wiedzieli, że jeśli to możliwe, powinni unikać korzystania z niego.
user276648
10
Powodem, dla którego przyszedłem na tę stronę, jest to, że zapytanie, które napisałem za pomocą instrukcji IN, było zbyt wolne. Zdecydowanie unikaj tutaj przyjętej odpowiedzi.
MikeKulls
4
Choć to stare pytanie jest ważne, ważne jest, aby wiedzieć, DLACZEGO powinieneś użyć opcji DOŁĄCZ zamiast IN. Kiedy ten warunek działa w wierszu, uruchomi to zapytanie wewnątrz IN. Oznacza to, że jeśli istnieje 100 wierszy, które należy sprawdzić w tym GDZIE, to podzapytanie zostanie uruchomione 100 razy. Natomiast JOIN będzie działał tylko RAZ. Tak więc, gdy twoja baza danych będzie coraz większa, zapytanie będzie trwać coraz dłużej. @markus tylko dlatego, że coś nie jest krytyczne, nie oznacza, że ​​powinieneś pisać zły kod. Pisanie go trochę lepiej zaoszczędzi ci dużo czasu i bólu głowy w przyszłości. :)
RisingSun
11

MySQL DELETE rekordy z JOIN

Zasadniczo używasz INNER JOIN w instrukcji SELECT, aby wybierać rekordy z tabeli, która ma odpowiadające rekordy w innych tabelach. Możemy również użyć klauzuli INNER JOIN z instrukcją DELETE, aby usunąć rekordy z tabeli, a także odpowiednie rekordy z innych tabel, np. Aby usunąć rekordy z tabel T1 i T2, które spełniają określony warunek, możesz użyć następującej instrukcji:

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

Zauważ, że wstawiasz nazwy tabel T1 i T2 między DELETE i FROM. Jeśli pominiesz tabelę T1, instrukcja DELETE usunie tylko rekordy w tabeli T2, a jeśli pominiesz tabelę T2, tylko rekordy w tabeli T1 zostaną usunięte.

Warunek łączenia T1.key = T2.key określa odpowiednie rekordy w tabeli T2, które należy usunąć.

Warunek w klauzuli WHERE określa, które rekordy w T1 i T2 należy usunąć.

Aman Garg
źródło
11

Usuwanie pojedynczej tabeli:

Aby usunąć wpisy z poststabeli:

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;

Aby usunąć wpisy z projectstabeli:

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;

Aby usunąć wpisy z clientstabeli:

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;

Usuń wiele tabel:

Aby usunąć wpisy z wielu tabel z połączonych wyników, należy podać nazwy tabel po DELETEliście rozdzielanej przecinkami:

Załóżmy, że chcesz usunąć wpisy z wszystkich trzech tabel ( posts, projects, clients) dla konkretnego klienta:

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
źródło
7

Spróbuj jak poniżej:

DELETE posts.*,projects.* 
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id;
Sangeetha Narayana Moorthy
źródło
4

Inną metodą usuwania przy użyciu wyboru podrzędnego, która jest lepsza niż użycie, INbyłabyWHERE EXISTS

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

Jednym z powodów, aby używać tego zamiast łączenia jest to, że a DELETEz JOINzabrania używania LIMIT. Jeśli chcesz usunąć w blokach, aby nie tworzyć pełnych blokad tabeli, możesz dodać LIMITDELETE WHERE EXISTSmetodę.

Jim Clouse
źródło
1
Czy to zapytanie można zapisać za pomocą „aliasów”? Ze składni nie wynika jasno, w jaki sposób funkcja postsEXISTS () jest taka sama posts, jak z której usuwane są wiersze. (W każdym razie IMHO)
MattBianco
Słyszę cię, ale w tabeli nie można usuwać aliasów. „Posty” w zapytaniu podrzędnym musi być pełną nazwą tabeli, co oznacza, że ​​jeśli chcesz ponownie użyć tej tabeli w klauzuli sub-select From, musisz ją tam aliasować.
Jim Clouse
1
Działa to: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);

USUŃ rekordy z jednej tabeli:

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

USUŃ ZAPISY Z obu tabel:

mysql> DELETE tb2,tb1 FROM tb2 JOIN tb1 USING(id);
zloctb
źródło
1

Jeśli dołączenie nie działa, możesz wypróbować to rozwiązanie. Służy do usuwania osieroconych rekordów z t1, gdy nie używa się kluczy obcych + specyficzny warunek where. To znaczy usuwa rekordy z tabeli 1, które mają puste pole „kod” i które nie mają rekordów w tabeli 2, pasujące do pola „nazwa”.

delete table1 from table1 t1 
    where  t1.code = '' 
    and 0=(select count(t2.name) from table2 t2 where t2.name=t1.name);
Kristjan Adojaan
źródło
0

Spróbuj tego,

DELETE posts.*
FROM posts
INNER JOIN projects ON projects.project_id = posts.project_id
WHERE projects.client_id = :client_id
Silambarasan
źródło
-3

- Pamiętaj, że nie możesz użyć aliasu nad tabelą, w której chcesz usunąć

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
źródło