Xóa bằng Tham gia vào MySQL


501

Đây là kịch bản để tạo các bảng của tôi:

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

Trong mã PHP của tôi, khi xóa một máy khách, tôi muốn xóa tất cả các bài viết của dự án:

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

Bảng bài viết không có khóa ngoại client_id, chỉ project_id. Tôi muốn xóa các bài viết trong các dự án đã thông qua client_id.

Điều này không hoạt động ngay bây giờ vì không có bài viết bị xóa.


10
Tôi nghĩ rằng câu trả lời của Yehosef phải là câu được chấp nhận, vì anh ta sử dụng Tham gia như bạn đã hỏi và nó hoạt động tốt hơn so với sử dụng mệnh đề IN như yukondude đề xuất ...
Gerardo Grignoli

2
Mẫu ưa thích là một DELETE posts FROM posts JOIN projects ..., chứ không phải là một IN (subquery)mẫu. (Câu trả lời từ Yehosef đưa ra một ví dụ về mẫu ưa thích.)
spencer7593

@GerardoGrignoli, nó hoạt động tốt hơn cho một công cụ hoặc phiên bản cụ thể của MySQL? Không có lý do tại sao hai truy vấn sẽ thực hiện bất kỳ khác nhau, vì AFAIK chúng giống hệt nhau. Tất nhiên, nếu tôi có niken mỗi lần trình tối ưu hóa truy vấn của tôi đã làm điều gì đó ngu ngốc ....
Paul Draper

Bạn cũng có thể sử dụng aliascho tên bảng và sử dụng đó.
biniam

Câu trả lời:


1254

Bạn chỉ cần xác định rằng bạn muốn xóa các mục từ postsbảng:

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

EDIT: Để biết thêm thông tin, bạn có thể xem câu trả lời thay thế này


117
Cần lưu ý rằng đây là câu trả lời chính xác vì tham gia buộc bạn phải sử dụng "XÓA bài đăng TỪ bài viết" thay vì "XÓA TỪ bài viết" thông thường, vì bảng cần xóa không còn rõ ràng. Cảm ơn!
siannopollo

8
Lưu ý rằng bạn không thể sử dụng phương thức 'as' ở đây, ví dụ: các dự án tham gia bên trong như p trên p.project_id ...
zzapper

14
Trên thực tế, bạn có thể sử dụng một bí danh cho các bảng đã tham gia, nhưng không phải cho bảng chính (bài viết). "XÓA bài đăng TỪ bài viết INNER THAM GIA dự án p ON p.project_id = post.project_id"
Weboide


14
đây là câu trả lời tốt nhất vì bạn thậm chí có thể xóa khỏi cả hai bảng trong một hành độngDELETE posts , projects FROM posts INNER JOIN projects ON projects.project_id = posts.project_id WHERE projects.client_id = :client_id
Developerium

84

Vì bạn đang chọn nhiều bảng, Bảng cần xóa không còn rõ ràng nữa. Bạn cần chọn :

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

Trong trường hợp này table_name1table_name2là cùng một bảng, vì vậy điều này sẽ hoạt động:

DELETE projects FROM posts INNER JOIN [...]

Bạn thậm chí có thể xóa từ cả hai bảng nếu bạn muốn:

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

Lưu ý rằng order bylimit không hoạt động để xóa nhiều bảng .

Cũng lưu ý rằng nếu bạn khai báo bí danh cho bảng, bạn phải sử dụng bí danh khi tham chiếu đến bảng:

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

Các khoản đóng góp từ Carpetsmoker và vv .


3
Nếu bạn đang trả lời tốt hơn - ít nhất bạn có thể làm cho SQL dễ đọc hơn. Tất cả các tham chiếu SQL khác trong câu hỏi này đều có từ khóa viết hoa (ngoại trừ một từ có 0 phiếu). Tôi không chắc tại sao bạn hoàn nguyên các chỉnh sửa của tôi.
Yehosef

3
@Yehosef, Có một nhóm người tìm thấy CAPS thực sự rực rỡ. Tôi tin rằng tôi không phải là người duy nhất, tôi cũng đã thấy khá nhiều người đi theo kiểu chữ thường.
Pacerier

1
đủ công bằng - Tôi tôn trọng quyền viết câu trả lời của bạn theo phong cách mà bạn thích;)
Yehosef

7
Để thêm vào thảo luận mũ / không giới hạn, đúng, bạn có thể sử dụng bất kỳ kiểu nào bạn thích, nhưng trong câu trả lời của bạn, bạn thực sự pha trộn các kiểu mà bạn thấy thuận tiện - ONđược viết hoa. Đối với các nhà phát triển ít kinh nghiệm, nó có thể chuyển tải rằng nó ổn khi lộn xộn và không nhất quán về kiểu dáng.
Bóng râm

16
TỪ KHÓA CAPS không chói. họ đang làm cho các câu hỏi có thể đọc được;)
Sachem

50

Hoặc điều tương tự, với cú pháp hơi khác (IMO thân thiện hơn):

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

BTW, với mysql sử dụng các phép nối hầu như luôn luôn nhanh hơn các truy vấn con ...


SỬ DỤNG có nghĩa là gì?
CMCDragonkai 30/03/2015


10
@ bigtex777: Xin lưu ý rằng từ khóa SỬ DỤNG trong các câu lệnh CHỌN ít liên quan đến cùng một từ khóa trong câu lệnh XÓA. Trong CHỌN, nó chỉ định danh sách các cột sẽ tham gia, trong khi trong XÓA, đó là danh sách tất cả các bảng trong một liên kết
ivanhoe

42

Bạn cũng có thể sử dụng ALIAS như thế này nó chỉ hoạt động trên cơ sở dữ liệu của tôi! t là bảng cần xóa từ!

DELETE t FROM posts t
INNER JOIN projects p ON t.project_id = p.project_id
AND t.client_id = p.client_id

1
điều này rất hữu ích khi tham gia khóa ghép để tránh lặp lại tên bảng
Marquez

1
"Trên thực tế, bạn có thể sử dụng bí danh cho các bảng đã tham gia, nhưng không phải cho bảng chính (bài đăng). 'XÓA bài đăng TỪ bài viết INNER THAM GIA dự án p ON p.project_id = post.project_id'" - @ Weboide
Jeaf Gilbert

2
Trên thực tế (trích dẫn từ dev.mysql.com/doc/refman/5.0/en/delete.html ) "Nếu bạn khai báo bí danh cho một bảng, bạn phải sử dụng bí danh khi tham khảo bảng: XÓA t1 TỪ kiểm tra AS t1, test2 WHERE ... "vì vậy sử dụng bí danh là tốt.
Peter Bowers

25

Tôi đã quen với giải pháp truy vấn con này hơn, nhưng tôi chưa thử nó trong MySQL:

DELETE  FROM posts
WHERE   project_id IN (
            SELECT  project_id
            FROM    projects
            WHERE   client_id = :client_id
        );

85
Bạn thực sự nên tránh sử dụng từ khóa IN trong SQL (mặc dù nó thường dễ hiểu hơn cho người mới bắt đầu) và sử dụng THAM GIA thay thế (khi có thể), vì các truy vấn con thường khiến mọi thứ chậm hơn rất nhiều.
dùng276648

14
Điều này có xu hướng làm sập DB khi có một số lượng lớn các hàng được trả về bởi truy vấn phụ. Nó cũng vô cùng chậm chạp.
Raj

2
@yukondude Thật vậy, "IN" dễ hiểu hơn rất nhiều so với "THAM GIA" ở lần đầu tiên, và đó là lý do tại sao những người không thực sự quen thuộc với SQL sẽ kết thúc việc viết "IN" ở mọi nơi, trong khi họ có thể sử dụng "THAM GIA" hoạt động tốt hơn ( hoặc rất nhiều whooole tốt hơn, tùy thuộc vào truy vấn). Tôi nhớ vài năm trước, gần như tất cả các truy vấn SQL của tôi sẽ được viết lại bởi một người thực sự biết cách viết các truy vấn tốt. Đó là lý do tại sao tôi đã thêm nhận xét để tránh "IN", để mọi người biết rằng nếu có thể, họ nên tránh sử dụng nó.
dùng276648

10
Lý do tôi đến trang này là vì truy vấn tôi đã viết với câu lệnh IN là con chó chậm. Chắc chắn tránh câu trả lời được chấp nhận ở đây.
MikeKulls

4
Vẫn như câu hỏi này, điều quan trọng là phải biết TẠI SAO bạn nên sử dụng THAM GIA thay vì IN. Khi điều kiện đó chạy trên một hàng, nó sẽ chạy truy vấn đó bên trong IN. Điều đó có nghĩa là, nếu có 100 hàng cần được kiểm tra dựa trên WHERE đó, truy vấn con đó sẽ được chạy 100 lần. Trong khi đó THAM GIA sẽ chỉ chạy ONCE. Vì vậy, khi db của bạn ngày càng lớn hơn, truy vấn đó sẽ mất nhiều thời gian hơn và lâu hơn để kết thúc. @markus chỉ vì điều gì đó không quan trọng không có nghĩa là bạn nên viết mã xấu. Viết nó tốt hơn một chút sẽ giúp bạn tiết kiệm rất nhiều thời gian và đau đầu trong tương lai. :)
risingsun

11

Bản ghi XÓA MySQL với THAM GIA

Bạn thường sử dụng INNER THAM GIA trong câu lệnh CHỌN để chọn các bản ghi từ một bảng có các bản ghi tương ứng trong các bảng khác. Chúng ta cũng có thể sử dụng mệnh đề INNER THAM GIA với câu lệnh DELETE để xóa các bản ghi khỏi một bảng và cả các bản ghi tương ứng trong các bảng khác, ví dụ, để xóa các bản ghi từ cả hai bảng T1 và T2 đáp ứng một điều kiện cụ thể, bạn sử dụng câu lệnh sau:

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

Lưu ý rằng bạn đặt tên bảng T1 và T2 giữa XÓA và TỪ. Nếu bạn bỏ qua bảng T1, câu lệnh DELETE chỉ xóa các bản ghi trong bảng T2 và nếu bạn bỏ qua bảng T2, chỉ các bản ghi trong bảng T1 sẽ bị xóa.

Điều kiện nối T1.key = T2.key chỉ định các bản ghi tương ứng trong bảng T2 cần xóa.

Điều kiện trong mệnh đề WHERE chỉ định những bản ghi nào trong T1 và T2 cần được xóa.


11

Xóa bảng đơn:

Để xóa các mục từ postsbảng:

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;

Để xóa các mục từ projectsbảng:

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;

Để xóa các mục từ clientsbảng:

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;

Xóa nhiều bảng:

Để xóa các mục từ nhiều bảng trong số các kết quả đã tham gia, bạn cần chỉ định tên bảng sau khi được DELETEliệt kê bằng dấu phẩy:

Giả sử bạn muốn xóa các mục từ tất cả các ba bảng ( posts, projects, clients) cho một khách hàng cụ thể:

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

7

Hãy thử như dưới đây:

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

4

Một phương pháp xóa khác bằng cách sử dụng một lựa chọn phụ tốt hơn so với sử dụng INsẽ làWHERE EXISTS

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

Một lý do để sử dụng này thay vì tham gia là một DELETEvới JOINcấm việc sử dụng LIMIT. Nếu bạn muốn xóa trong các khối để không tạo ra các khóa bảng đầy đủ, bạn có thể thêm LIMITsử dụng DELETE WHERE EXISTSphương pháp này .


1
Truy vấn này có thể được viết bằng "bí danh" không? Không rõ ràng về cú pháp làm thế nào poststrong EXISTS () giống postsvới các hàng bị xóa khỏi. (IMHO anyway)
MattBianco

Tôi nghe thấy bạn, nhưng bí danh không được phép trong bảng để xóa khỏi. "Bài viết" trong truy vấn phụ phải là tên bảng đầy đủ, điều đó có nghĩa là nếu bạn muốn sử dụng lại bảng đó trong mệnh đề chọn phụ của bạn, bạn phải đặt bí danh cho nó ở đó.
Jim Clouse

1
Công việc này: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);

XÓA hồ sơ TỪ một bảng:

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

XÓA HỒ SƠ TỪ cả hai bảng:

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

1

Nếu tham gia không hiệu quả với bạn, bạn có thể thử giải pháp này. Đó là để xóa các bản ghi mồ côi từ t1 khi không sử dụng khóa ngoại + điều kiện cụ thể. Tức là nó xóa các bản ghi khỏi bảng1, có "mã" trường trống và không có các bản ghi trong bảng2, khớp với trường "tên".

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

0

Thử cái này,

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

-3

- Lưu ý rằng bạn không thể sử dụng bí danh trên bảng nơi bạn cần xóa

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.