MySQL, cập nhật nhiều bảng với một truy vấn


132

Tôi có một chức năng cập nhật ba bảng, nhưng tôi sử dụng ba truy vấn để thực hiện điều này. Tôi muốn sử dụng một cách tiếp cận thuận tiện hơn để thực hành tốt.

Làm cách nào để cập nhật nhiều bảng trong MySQL bằng một truy vấn?


3
bạn có thể cung cấp một ví dụ về mã được tạo ra? Có một khóa chung giữa các bảng?
Ngày Jonathan

Câu trả lời:


451

Lấy trường hợp của hai bảng, BooksOrders. Trong trường hợp, chúng tôi tăng số lượng sách theo một thứ tự cụ thể với Order.ID = 1002trong Ordersbảng thì chúng tôi cũng cần giảm tổng số sách có sẵn trong kho của chúng tôi bằng cùng một số trong Booksbảng.

UPDATE Books, Orders
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE
    Books.BookID = Orders.BookID
    AND Orders.OrderID = 1002;

Nếu tôi muốn bao gồm "GIỚI HẠN" cho Truy vấn SQL, tôi có phải nói GIỚI HẠN 1 hoặc GIỚI HẠN 2 không?
Bluedayz

2
Lợi thế của việc này so với giao dịch là gì? Cảm ơn!
paulkon

2
@paulkon, tôi giả sử rằng khi sử dụng các giao dịch, có rất nhiều chi phí liên quan vì các giao dịch phải có sẵn nếu bất kỳ thủ tục nào trong giao dịch không thành công.
Thijs Riezebeek

27
Cảnh báo chung khi sử dụng truy vấn này. Mệnh đề WHERE được ước tính riêng cho từng bảng. Sách.BookID = Đơn hàng.BookID rất quan trọng, nếu không có nó Việc cập nhật bảng Sách sẽ xảy ra với tất cả các hàng và không chỉ cho hàng có id được chỉ định. Một số bài học được học một cách khó khăn, bài học này được học theo cách đáng sợ.
nheimann1

1
@ nheimann1 Và đó chính xác là lý do tại sao tôi luôn khuyên mọi người sử dụng cú pháp "tham gia bên trong" ANSI. Thật quá dễ dàng để quên điều kiện đó và thay vào đó hãy tham gia Cartesian đầy đủ.
lừa4jesus

77
UPDATE t1
INNER JOIN t2 ON t2.t1_id = t1.id
INNER JOIN t3 ON t2.t3_id = t3.id
SET t1.a = 'something',
    t2.b = 42,
    t3.c = t2.c
WHERE t1.a = 'blah';

Để xem những gì sẽ được cập nhật, bạn có thể chuyển đổi nó thành một câu lệnh chọn, ví dụ:

SELECT t2.t1_id, t2.t3_id, t1.a, t2.b, t2.c AS t2_c, t3.c AS t3_c
FROM t1
INNER JOIN t2 ON t2.t1_id = t1.id
INNER JOIN t3 ON t2.t3_id = t3.id
WHERE t1.a = 'blah';

Một ví dụ sử dụng các bảng giống như câu trả lời khác:

SELECT Books.BookID, Orders.OrderID,
    Orders.Quantity AS CurrentQuantity,
    Orders.Quantity + 2 AS NewQuantity,
    Books.InStock AS CurrentStock,
    Books.InStock - 2 AS NewStock
FROM Books
INNER JOIN Orders ON Books.BookID = Orders.BookID
WHERE Orders.OrderID = 1002;

UPDATE Books
INNER JOIN Orders ON Books.BookID = Orders.BookID
SET Orders.Quantity = Orders.Quantity + 2,
    Books.InStock = Books.InStock - 2
WHERE Orders.OrderID = 1002;

BIÊN TẬP:

Để cho vui, hãy thêm một cái gì đó thú vị hơn một chút.

Giả sử bạn có một bảng booksvà một bảng authors. Bạn bookscó một author_id. Nhưng khi cơ sở dữ liệu ban đầu được tạo, không có ràng buộc khóa ngoại nào được thiết lập và sau đó là một lỗi trong mã mặt trước khiến một số sách được thêm vào với author_ids không hợp lệ . Là một DBA, bạn không muốn phải trải qua tất cả những điều này booksđể kiểm tra xem điều gì author_idnên xảy ra, vì vậy quyết định được đưa ra là người thu thập dữ liệu sẽ sửa lỗi booksđể chỉ về bên phải authors. Nhưng có quá nhiều cuốn sách để đi qua từng cuốn sách và giả sử bạn biết rằng những cuốn sách author_idtương ứng với thực tế authorlà chính xác. Nó chỉ là những cái không tồn tạiauthor_ids không hợp lệ Hiện đã có giao diện cho người dùng cập nhật chi tiết sách và nhà phát triển không muốn thay đổi chỉ dành cho vấn đề này. Nhưng giao diện hiện có làm một INNER JOIN authors, vì vậy tất cả các cuốn sách có tác giả không hợp lệ đều bị loại trừ.

Những gì bạn có thể làm là thế này: Chèn một bản ghi tác giả giả như "Tác giả không xác định". Sau đó cập nhật author_idtất cả các hồ sơ xấu để trỏ đến tác giả Unknown. Sau đó, người thu thập dữ liệu có thể tìm kiếm tất cả các cuốn sách với tác giả được đặt thành "Tác giả không xác định", tìm kiếm tác giả chính xác và sửa chúng.

Làm thế nào để bạn cập nhật tất cả các hồ sơ xấu để trỏ đến tác giả chưa biết? Như thế này (giả sử tác giả Unknown author_idlà 99999):

UPDATE books
LEFT OUTER JOIN authors ON books.author_id = authors.id
SET books.author_id = 99999
WHERE authors.id IS NULL;

Ở trên cũng sẽ cập nhật bookscó một NULL author_idtác giả chưa biết. Nếu bạn không muốn điều đó, tất nhiên bạn có thể thêm AND books.author_id IS NOT NULL.


35

Bạn cũng có thể thực hiện điều này với một truy vấn bằng cách sử dụng liên kết như vậy:

UPDATE table1,table2 SET table1.col=a,table2.col2=b
WHERE items.id=month.id;

Và sau đó chỉ cần gửi một truy vấn này, tất nhiên. Bạn có thể đọc thêm về tham gia tại đây: http://dev.mysql.com/doc/refman/5.0/en/join.html . Ngoài ra còn có một số hạn chế đối với việc đặt hàng và giới hạn đối với nhiều bản cập nhật bảng bạn có thể đọc về đây: http://dev.mysql.com/doc/refman/5.0/en/update.html (chỉ cần ctrl + f "tham gia").


Thật hào phóng khi gọi đó là "tham gia" ;-)
gạch dưới

2

Đó thường là những gì các thủ tục được lưu trữ dành cho: để thực hiện một số câu lệnh SQL theo một trình tự. Sử dụng rollback, bạn có thể đảm bảo rằng chúng được coi là một đơn vị công việc, tức là tất cả chúng đều được thực thi hoặc không có cái nào trong số chúng, để giữ cho dữ liệu nhất quán.


Tôi sẽ viết thủ tục ở đâu? bạn có thể vui lòng cung cấp một ví dụ?
Adamski

1
Được bình chọn để giải thích sự cần thiết của nguyên tử - điều quan trọng là phải nhận ra rằng việc sử dụng các thủ tục được lưu trữ không chỉ đảm bảo tính nhất quán, bạn vẫn cần sử dụng các giao dịch; tương tự, các giao dịch có thể được thực hiện mà không cần sử dụng một thủ tục được lưu trữ, miễn là chúng được thực hiện trên cùng một kết nối. Trong trường hợp này, việc sử dụng một bản cập nhật nhiều bảng thậm chí còn tốt hơn.
Duncan

2

Khi bạn nói nhiều truy vấn, bạn có nghĩa là nhiều câu lệnh SQL như trong:

UPDATE table1 SET a=b WHERE c;
UPDATE table2 SET a=b WHERE d;
UPDATE table3 SET a=b WHERE e;

Hoặc nhiều hàm gọi truy vấn như trong:

mySqlQuery(UPDATE table1 SET a=b WHERE c;)
mySqlQuery(UPDATE table2 SET a=b WHERE d;)
mySqlQuery(UPDATE table3 SET a=b WHERE e;)

Tất cả trước đây có thể được thực hiện bằng một lệnh gọi mySqlQuery nếu đó là những gì bạn muốn đạt được, chỉ cần gọi hàm mySqlQuery theo cách sau:

mySqlQuery(UPDATE table1 SET a=b WHERE c; UPDATE table2 SET a=b WHERE d; UPDATE table3 SET a=b WHERE e;)

Điều này sẽ thực hiện cả ba truy vấn với một lệnh gọi mySqlQuery ().


mySqlQuery () là một hàm tùy chỉnh hoặc trong hàm dựng sẵn? Tôi muốn biết thêm về điều này.
Debashis

3
Không có sự khác biệt đáng kể giữa việc gửi ba truy vấn riêng lẻ hoặc dưới dạng nhiều truy vấn, ngoại trừ có lẽ nếu chức năng truy vấn của bạn mở một kết nối mới mỗi lần. Từ quan điểm thực hiện phía máy chủ, đó là điều tương tự
Duncan
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.