MySQL อัปเดตหลายตารางด้วยแบบสอบถามเดียว


132

ฉันมีฟังก์ชันที่อัปเดตตารางสามตาราง แต่ฉันใช้แบบสอบถามสามรายการเพื่อดำเนินการนี้ ฉันต้องการใช้แนวทางที่สะดวกกว่าในการปฏิบัติที่ดี

ฉันจะอัปเดตหลายตารางใน MySQL ด้วยแบบสอบถามเดียวได้อย่างไร


3
คุณสามารถให้ตัวอย่างของรหัสที่สร้างขึ้นได้หรือไม่? มีคีย์ทั่วไประหว่างตารางหรือไม่?
Jonathan Day

คำตอบ:


451

ใช้กรณีของตารางสองตารางBooksและOrders. ในกรณีที่เราเพิ่มจำนวนหนังสือตามลำดับที่ระบุOrder.ID = 1002ในOrdersตารางจากนั้นเราจำเป็นต้องลดจำนวนหนังสือทั้งหมดที่มีอยู่ในสต็อกของเราด้วยจำนวนเดียวกันในBooksตาราง

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

ถ้าฉันต้องการรวม "LIMIT" ในการสืบค้น SQL ฉันต้องพูด LIMIT 1 หรือ LIMIT 2 หรือไม่
Bluedayz

2
ข้อดีของการทำธุรกรรมกับธุรกรรมคืออะไร? ขอบคุณ!
paulkon

2
@ paulkon ฉันคิดว่าเมื่อใช้ธุรกรรมมีค่าใช้จ่ายจำนวนมากที่เกี่ยวข้องเนื่องจากต้องมีการย้อนกลับหากขั้นตอนใด ๆ ในธุรกรรมล้มเหลว
Thijs Riezebeek

27
คำเตือนทั่วไปเมื่อใช้แบบสอบถามนี้ คำสั่ง WHERE ได้รับการประเมินแยกกันสำหรับแต่ละตาราง Books.BookID = Orders.BookID มีความสำคัญมากหากไม่มีการอัปเดตตารางหนังสือจะเกิดขึ้นกับทุกแถวและไม่เพียง แต่สำหรับแถวที่มีรหัสที่ระบุเท่านั้น บางบทเรียนเรียนรู้ด้วยวิธีที่ยากลำบากบทเรียนนี้ได้เรียนรู้ด้วยวิธีที่น่ากลัว
nheimann1

1
@ nheimann1 และนั่นคือเหตุผลว่าทำไมฉันจึงแนะนำให้คนใช้ไวยากรณ์ "inner join" ของ ANSI อยู่เสมอ ง่ายเกินไปที่จะลืมเงื่อนไขนั้นและเข้าร่วมคาร์ทีเซียนเต็มรูปแบบแทน
fool4jesus

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

หากต้องการดูว่ากำลังจะอัปเดตอะไรคุณสามารถแปลงสิ่งนี้เป็นคำสั่งที่เลือกได้เช่น:

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

ตัวอย่างที่ใช้ตารางเดียวกันกับคำตอบอื่น ๆ :

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;

แก้ไข:

เพื่อความสนุกสนานขอเพิ่มสิ่งที่น่าสนใจอีกเล็กน้อย

สมมติว่าคุณมีตารางของและโต๊ะของbooks authorsของคุณbooksมีauthor_idไฟล์. แต่เมื่อฐานข้อมูลถูกสร้างขึ้นในตอนแรกไม่มีการตั้งค่าข้อ จำกัด ของคีย์ต่างประเทศและต่อมาข้อผิดพลาดในโค้ดส่วนหน้าทำให้หนังสือบางเล่มถูกเพิ่มด้วยauthor_ids ที่ไม่ถูกต้อง ในฐานะที่เป็น DBA ที่คุณไม่ต้องการที่จะต้องไปผ่านสิ่งเหล่านี้booksเพื่อตรวจสอบว่าสิ่งที่author_idควรจะเป็นเพื่อการตัดสินใจที่จะทำว่า capturers ข้อมูลจะแก้ไขไปยังจุดไปทางขวาbooks authorsแต่มีหนังสือจำนวนมากเกินไปที่จะอ่านแต่ละเล่มและสมมติว่าคุณรู้ว่าหนังสือที่มีauthor_idที่สอดคล้องกับจริงauthorนั้นถูกต้อง มันเป็นเพียงสิ่งที่ไม่มีอยู่จริงauthor_ids ที่ไม่ถูกต้อง มีอินเทอร์เฟซสำหรับผู้ใช้ในการอัปเดตรายละเอียดหนังสืออยู่แล้วและนักพัฒนาไม่ต้องการเปลี่ยนแปลงเพียงเพื่อปัญหานี้ แต่อินเทอร์เฟซที่มีอยู่ทำหน้าที่INNER JOIN authorsได้ดังนั้นหนังสือทั้งหมดที่มีผู้แต่งไม่ถูกต้องจะถูกยกเว้น

สิ่งที่ทำได้คือใส่บันทึกผู้แต่งปลอมเช่น "Unknown author" จากนั้นอัปเดตauthor_idบันทึกที่ไม่ดีทั้งหมดเพื่อชี้ไปที่ผู้เขียนที่ไม่รู้จัก จากนั้นตัวจับข้อมูลสามารถค้นหาหนังสือทั้งหมดโดยตั้งค่าผู้เขียนเป็น "ผู้เขียนที่ไม่รู้จัก" ค้นหาผู้แต่งที่ถูกต้องและแก้ไข

คุณจะอัปเดตบันทึกที่ไม่ดีทั้งหมดให้ชี้ไปที่ผู้เขียนที่ไม่รู้จักได้อย่างไร เช่นนี้ (สมมติว่าผู้เขียนไม่ทราบชื่อauthor_idคือ 99999):

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

ข้างต้นจะมีการอัปเดตbooksที่มีNULL author_idถึงผู้เขียนที่ไม่รู้จัก หากคุณไม่ต้องการสิ่งนั้นคุณสามารถเพิ่มAND books.author_id IS NOT NULLได้


35

คุณสามารถทำได้ด้วยแบบสอบถามเดียวเช่นกันโดยใช้การเข้าร่วมดังนี้:

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

จากนั้นก็ส่งแบบสอบถามนี้แน่นอน คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการเข้าร่วมที่นี่: http://dev.mysql.com/doc/refman/5.0/en/join.html นอกจากนี้ยังมีข้อ จำกัด บางประการสำหรับการสั่งซื้อและการ จำกัด การอัปเดตตารางหลายรายการที่คุณสามารถอ่านได้ที่นี่: http://dev.mysql.com/doc/refman/5.0/th/update.html (เพียง ctrl + f "join")


ขอเรียกสิ่งนั้นว่า "join" ;-)
underscore_d

2

โดยปกติขั้นตอนการจัดเก็บนั้นมีไว้สำหรับ: เพื่อใช้คำสั่ง SQL หลายคำสั่งตามลำดับ การใช้การย้อนกลับคุณสามารถมั่นใจได้ว่าจะถือว่าเป็นหน่วยงานเดียวกล่าวคือดำเนินการทั้งหมดหรือไม่มีเลยเพื่อให้ข้อมูลมีความสอดคล้องกัน


ฉันจะเขียนขั้นตอนได้ที่ไหน คุณช่วยยกตัวอย่างได้ไหม
Adamski

1
ได้รับการโหวตให้อธิบายถึงความจำเป็นของปรมาณู - สิ่งสำคัญคือต้องตระหนักว่าการใช้ขั้นตอนที่จัดเก็บไว้ไม่ได้รับประกันความสม่ำเสมอเพียงอย่างเดียวคุณยังต้องใช้ธุรกรรม ในทำนองเดียวกันสามารถทำธุรกรรมได้โดยไม่ต้องใช้กระบวนงานที่จัดเก็บหากดำเนินการผ่านการเชื่อมต่อเดียวกัน ในกรณีนี้การใช้การอัปเดตแบบหลายตารางจะดียิ่งขึ้น
Duncan

2

เมื่อคุณพูดหลายแบบสอบถามคุณหมายถึงคำสั่ง SQL หลายคำใน:

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

หรือเรียกใช้ฟังก์ชันการสืบค้นหลายรายการในรูปแบบ:

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

ก่อนหน้านี้สามารถทำได้โดยใช้การเรียก mySqlQuery เดียวหากนั่นคือสิ่งที่คุณต้องการบรรลุเพียงแค่เรียกใช้ฟังก์ชัน mySqlQuery ในลักษณะต่อไปนี้:

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

สิ่งนี้จะดำเนินการทั้งสามแบบสอบถามด้วยการเรียก mySqlQuery () ครั้งเดียว


mySqlQuery () เป็นฟังก์ชันที่กำหนดเองหรือในฟังก์ชันที่สร้างขึ้น ฉันต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้
Debashis

3
ไม่มีความแตกต่างอย่างมีนัยสำคัญระหว่างการส่งแบบสอบถามสามรายการทีละรายการหรือเป็นแบบสอบถามหลายรายการยกเว้นในกรณีที่ฟังก์ชันการสืบค้นของคุณเปิดการเชื่อมต่อใหม่ทุกครั้ง จากมุมมองของการดำเนินการฝั่งเซิร์ฟเวอร์ก็เหมือนกัน
Duncan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.