จะลบจากหลายตารางใน MySQL ได้อย่างไร?


117

ฉันกำลังพยายามลบจากสองสามตารางพร้อมกัน ฉันได้ทำการค้นคว้าและหาข้อมูลมาเล็กน้อย

DELETE FROM `pets` p,
            `pets_activities` pa
      WHERE p.`order` > :order
        AND p.`pet_id` = :pet_id
        AND pa.`id` = p.`pet_id`

อย่างไรก็ตามฉันได้รับข้อผิดพลาดนี้

Uncaught Database_Exception [1064]: คุณมีข้อผิดพลาดในไวยากรณ์ SQL ของคุณ ตรวจสอบคู่มือที่สอดคล้องกับเวอร์ชันเซิร์ฟเวอร์ MySQL ของคุณสำหรับไวยากรณ์ที่เหมาะสมที่จะใช้ใกล้ 'p, pets_activitiespa ...

ฉันไม่เคยลบตารางไขว้มาก่อนดังนั้นฉันจึงไม่มีประสบการณ์และติดอยู่ในตอนนี้!

ผมทำอะไรผิดหรือเปล่า?

คำตอบ:


205

ใช้คำสั่งJOINในDELETEคำสั่ง

DELETE p, pa
      FROM pets p
      JOIN pets_activities pa ON pa.id = p.pet_id
     WHERE p.order > :order
       AND p.pet_id = :pet_id

หรือคุณสามารถใช้ ...

DELETE pa
      FROM pets_activities pa
      JOIN pets p ON pa.id = p.pet_id
 WHERE p.order > :order
   AND p.pet_id = :pet_id

... เพื่อลบจาก pets_activities

ดูนี้

สำหรับการลบตารางเดียว แต่ด้วยความซื่อสัตย์สุจริตอ้างอิงมีวิธีการอื่น ๆ ของการทำกับEXISTS, NOT EXISTS, IN, NOT INและอื่น ๆ แต่อย่างใดอย่างหนึ่งดังกล่าวข้างต้นที่คุณระบุจากตารางลบด้วยนามแฝงก่อนที่FROMข้อจะได้รับคุณออกจากสวยแน่นไม่กี่ จุดได้ง่ายขึ้น ฉันมักจะเข้าถึงEXISTS99% ของกรณีและมี 1% ที่ไวยากรณ์ MySQL นี้ใช้เวลาทั้งวัน


7
ฉันลอง "ลบทั้งหมดใน 1 แบบสอบถาม" โดยรวม 6 ตารางใหญ่ (ทุกคนประมาณ 15k แถว) และแบบสอบถามใช้เวลา 155 วินาทีในการลบ 63 แถวใน 6 ตาราง: O
Klemen Tušar

1
@cadman นี่คือคำตอบที่แท้จริง อาจมีข้อโต้แย้งในการใช้ แต่บางครั้งก็มีประโยชน์มาก
Simon Christian

1
+1 ฉันยอมรับว่านี่เป็นคำตอบที่ถูกต้องเนื่องจากคำถามไม่ใช่ "คุณควร" แต่เป็น "วิธีการ" อย่างไรก็ตามฉันสนใจที่จะได้ยินเกี่ยวกับ 1% เพราะฉันไม่สามารถนึกถึงสถานการณ์เดียวที่จะเป็นเช่นนี้ได้
Erick Robertson

2
@techouse คุณเข้าร่วมและกรองดัชนีหรือไม่? 15k x 15k x 15k x 15k 15k x 15k คือ 11 ล้าน ได้SELECTใช้เวลาในทำนองเดียวกันยาว?
Paul Draper

6
คุณยังสามารถใช้ LEFT JOIN ซึ่งจะมีประโยชน์หากตารางที่สองไม่มีรายการที่ตรงกันมิฉะนั้นจะไม่มีการลบ
Lexib0y

20

เนื่องจากปรากฏขึ้นนี้จะมีความสัมพันธ์แม่ / ลูกง่ายระหว่างpetsและpets_activitiesคุณจะดีกว่าการสร้างข้อ จำกัด ที่สำคัญต่างประเทศของคุณกับน้ำตกลบ

ด้วยวิธีนี้เมื่อมีการpetsลบpets_activitiesแถวแถวที่เกี่ยวข้องจะถูกลบโดยอัตโนมัติเช่นกัน

จากนั้นคำถามของคุณจะกลายเป็นเรื่องง่าย:

delete from `pets`
    where `order` > :order
      and `pet_id` = :pet_id

3
@Erick หากคุณได้ตั้งค่าความสมบูรณ์ของการอ้างอิงการลบแบบเรียงซ้อนจะทำให้ไม่มีปัญหามากไปกว่าการลบด้วยตัวเอง เรารู้แล้วว่าpaเป็นลูกที่เหมาะสมpเนื่องจากการid/pet_idทำแผนที่
paxdiablo

14
พวกคุณมีความคิดของตัวเอง แต่ดูเหมือนว่าคุณจะลดพลังของ DBMS ลงไปมาก การลบแบบเรียงซ้อนเป็นส่วนหนึ่งของการจัดการข้อมูลเช่นเดียวกับทริกเกอร์ขั้นตอนที่จัดเก็บหรือข้อ จำกัด และจะเป็นอันตรายหากคุณไม่รู้ว่ากำลังทำอะไรอยู่ ถึงกระนั้นฉันจะไม่เถียงประเด็นนี้ต่อไปเราก็แค่เห็นด้วยกับไม่เห็นด้วย
paxdiablo

8
เอริคตอนนี้คุณทำให้ฉันสนใจ คุณจะตรวจสอบความสมบูรณ์ของข้อมูลภายในฐานข้อมูลโดยไม่มีข้อ จำกัด ได้อย่างไร?
paxdiablo

4
@Erick กล่าวว่า "ฉันยังไม่ใช้ทริกเกอร์กระบวนงานที่เก็บไว้หรือข้อ จำกัด " อ่าคุณใช้ Excel :-)
james.garriss

4
ฉันแค่อยากติดตามเรื่องนี้ ฉันได้เปลี่ยนตำแหน่งของฉันในการลบน้ำตกในสถานการณ์นี้ ฉันเป็นส่วนหนึ่งของสภาพแวดล้อม SQL ใหม่ที่ใช้และใช้งานได้ดีและมีระเบียบมาก ในระบบนี้มันทำงานได้ดีมากเพื่อประโยชน์ของเราที่จะมีน้ำตกเหล่านี้เข้าที่ แน่นอนว่ามันป้องกันข้อมูลที่ถูกทอดทิ้งและไม่เป็นอันตราย ปัญหาคือทุกคนที่ทำงานกับฐานข้อมูลจำเป็นต้องเข้าใจวิธีใช้อย่างปลอดภัย แต่มีความเสี่ยงเสมอเมื่อผู้พัฒนารุ่นเยาว์ทำการเปลี่ยนแปลงฐานข้อมูลโดยไม่ได้รับการดูแล
Erick Robertson

14

ใช้สิ่งนี้

DELETE FROM `articles`, `comments` 
USING `articles`,`comments` 
WHERE `comments`.`article_id` = `articles`.`id` AND `articles`.`id` = 4

หรือ

DELETE `articles`, `comments` 
FROM `articles`, `comments` 
WHERE `comments`.`article_id` = `articles`.`id` AND `articles`.`id` = 4

1
พบข้อมูลอ้างอิงที่ดีสำหรับการใช้สิ่งนี้และตัวเลือกอื่น ๆ ที่mysqltutorial.org/mysql-delete-statement.aspx
Mavelo

3

ฉันไม่มีฐานข้อมูล mysql ที่จะทดสอบในขณะนี้ แต่คุณได้ลองระบุสิ่งที่จะลบก่อนส่วนคำสั่ง from หรือไม่? ตัวอย่างเช่น:

DELETE p, pa FROM `pets` p,
        `pets_activities` pa
  WHERE p.`order` > :order
    AND p.`pet_id` = :pet_id
    AND pa.`id` = p.`pet_id`

ฉันคิดว่าไวยากรณ์ที่คุณใช้นั้น จำกัด เฉพาะ mysql เวอร์ชันใหม่กว่า


1
อย่างไรก็ตามการสืบค้นดังกล่าวดำเนินการสำเร็จ แต่ไม่ได้ลบแถวใด ๆ (แต่ฉันเชื่อว่าควรมี)
alex

2

ไวยากรณ์ดูเหมาะกับฉัน ... ลองเปลี่ยนมาใช้INNER JOIN...

มีลักษณะที่นี้


7
เสียดายที่คุณไม่ได้ใส่วิธีแก้ปัญหาจริงเนื่องจากลิงค์ถูกต้อง!
mycroes

1

สำหรับทุกคนที่อ่านสิ่งนี้ในปี 2560 นี่คือวิธีที่ฉันได้ทำสิ่งที่คล้ายกัน

DELETE pets, pets_activities FROM pets inner join pets_activities
on pets_activities.id = pets.id WHERE pets.`order` > :order AND 
pets.`pet_id` = :pet_id

โดยทั่วไปในการลบแถวจากหลายตารางไวยากรณ์ที่ฉันปฏิบัติตามจะได้รับด้านล่าง การแก้ปัญหาอยู่บนสมมติฐานที่ว่ามีความสัมพันธ์บางอย่างระหว่างสองตาราง

DELETE table1, table2 FROM table1 inner join table2 on table2.id = table1.id
WHERE [conditions]

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