ฉันจะลบจากหลายตารางโดยใช้ INNER JOIN ใน SQL server ได้อย่างไร


คำตอบ:


119

คุณสามารถใช้ประโยชน์จากตารางหลอก "ลบ" ในตัวอย่างนี้ สิ่งที่ต้องการ:

begin transaction;

   declare @deletedIds table ( id int );

   delete from t1
   output deleted.id into @deletedIds
   from table1 as t1
    inner join table2 as t2
      on t2.id = t1.id
    inner join table3 as t3
      on t3.id = t2.id;

   delete from t2
   from table2 as t2
    inner join @deletedIds as d
      on d.id = t2.id;

   delete from t3
   from table3 as t3 ...

commit transaction;

เห็นได้ชัดว่าคุณสามารถ 'ลบผลลัพธ์' ได้ ในการลบครั้งที่สองเช่นกันหากคุณต้องการบางสิ่งเพื่อเข้าร่วมสำหรับตารางที่สาม

ในฐานะบันทึกด้านข้างคุณยังสามารถแทรก. * ในคำสั่งแทรกและทั้งแทรก. * และลบ. * ในคำสั่งอัพเดต

แก้ไข: นอกจากนี้คุณได้พิจารณาเพิ่มทริกเกอร์บน table1 เพื่อลบออกจาก table2 + 3 หรือไม่ คุณจะอยู่ในธุรกรรมโดยปริยายและจะมีตารางหลอก"แทรก" และ "ลบ " ด้วย


2
จะดีกว่าไหมที่จะลบจาก table1 WHERE id = x แล้วลบจากตารางถัดไปแทนที่จะใช้การรวมภายในและดำเนินการผ่านข้อความพิเศษทั้งหมดนี้ โดยพื้นฐานแล้วการข้ามการเข้าร่วมภายในฉันต้องการเพียง 2 แบบสอบถามง่ายๆ .... หรือวิธีนี้มีประสิทธิภาพมากกว่านี้?
Colandus

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

@JohnGibb คำตอบนี้ทำงานอย่างไร? คุณสามารถอธิบายคำตอบนี้เพื่อให้นักพัฒนา MySQL เข้าใจได้หรือไม่?
Pacerier

@Pacerier ฉันไม่ค่อยคุ้นเคยกับ MySQL แนวคิดคือการลบครั้งแรกเป็นการลบจาก table1 เท่านั้น แต่เป็นการบันทึก ID ที่ถูกลบลงในตัวแปร สองคำสั่งที่ตามมาจะใช้ตัวแปรนั้นเพื่อลบแถวที่เกี่ยวข้องจาก table2 และตารางที่ 3 ได้อย่างไร
John Gibb

@JohnGibb ตอนนี้ที่ชัดเจน คุณควรรวมไว้ในคำตอบ
Pacerier

15
  1. คุณสามารถตั้งค่าการลบแบบเรียงซ้อนบนความสัมพันธ์ของตารางได้ตลอดเวลา

  2. คุณสามารถห่อหุ้มการลบหลายรายการในขั้นตอนเดียวที่เก็บไว้

  3. คุณสามารถใช้ธุรกรรมเพื่อให้แน่ใจว่ามีการทำงานหนึ่งหน่วย


3
เป็นไปได้อย่างแน่นอนที่จะลบในคำสั่ง join ฉันแค่ต้องการลบจากมากกว่าหนึ่งตารางในแต่ละครั้ง
Byron Whitlock

ตอบผิดสามารถใช้
join

โฆษณา 1. ) นั่นไม่เป็นความจริงอาจเป็นไปไม่ได้เสมอไป มีบางสถานการณ์ที่คุณไม่สามารถตั้งค่าการลบแบบเรียงซ้อนได้เช่นรอบหรือเส้นทางแบบเรียงซ้อน (ดูstackoverflow.com/a/3548225/108374เป็นต้น)
Tom Pažourek

15

คุณสามารถใช้ไวยากรณ์ JOIN ในส่วนคำสั่ง FROM ใน DELETE ใน SQL Server แต่คุณยังคงลบออกจากตารางแรกเท่านั้นและเป็นส่วนขยาย Transact-SQL ที่เป็นกรรมสิทธิ์ซึ่งเป็นทางเลือกแทนแบบสอบถามย่อย

จากตัวอย่างที่นี่ :

 -- Transact-SQL extension
 DELETE 
   FROM Sales.SalesPersonQuotaHistory 
     FROM Sales.SalesPersonQuotaHistory AS spqh INNER JOIN 
          Sales.SalesPerson AS sp ON spqh.BusinessEntityID = sp.BusinessEntityID
    WHERE sp.SalesYTD > 2500000.00;

3
ตัวอย่าง D: DELETE FROM Sales.SalesPersonQuotaHistory FROM Sales.SalesPersonQuotaHistory AS spqh INNER JOIN Sales.SalesPerson AS sp ON spqh.BusinessEntityID = sp.BusinessEntityID WHERE sp.SalesYTD> 2500000.00;
Mark A

11

ตัวอย่างการลบบางระเบียนจากตารางหลักและระเบียนที่เกี่ยวข้องจากตารางรายละเอียดสองตาราง:

BEGIN TRAN

  -- create temporary table for deleted IDs
  CREATE TABLE #DeleteIds (
    Id INT NOT NULL PRIMARY KEY
  )

  -- save IDs of master table records (you want to delete) to temporary table    
  INSERT INTO #DeleteIds(Id)
  SELECT DISTINCT mt.MasterTableId
  FROM MasterTable mt 
  INNER JOIN ... 
  WHERE ...  

  -- delete from first detail table using join syntax
  DELETE d
  FROM DetailTable_1 D
  INNER JOIN #DeleteIds X
    ON D.MasterTableId = X.Id


  -- delete from second detail table using IN clause  
  DELETE FROM DetailTable_2
  WHERE MasterTableId IN (
    SELECT X.Id
    FROM #DeleteIds X
  )


  -- and finally delete from master table
  DELETE d
  FROM MasterTable D
  INNER JOIN #DeleteIds X
    ON D.MasterTableId = X.Id

  -- do not forget to drop the temp table
  DROP TABLE #DeleteIds

COMMIT

1
ใช้SELECT INTO #DeleteIdsแทนCREATE TABLE 'DeleteIdsตามด้วยได้INSERT INTO 'DeleteIds...ไหม
Caltor

9

แค่สงสัยว่า .. เป็นไปได้จริงใน MySQL? มันจะลบ t1 และ t2? หรือฉันแค่เข้าใจคำถามผิด

แต่ถ้าคุณแค่ต้องการลบ table1 ที่มีเงื่อนไขการรวมหลาย ๆ เงื่อนไขก็อย่าใช้แทนตารางที่คุณต้องการลบ

นี้:

DELETE t1,t2 
FROM table1 AS t1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

ควรเขียนแบบนี้เพื่อทำงานใน MSSQL:

DELETE table1
FROM table1 
INNER JOIN table2 t2 ...
INNER JOIN table3 t3 ...

เพื่อเปรียบเทียบว่า RDBMS ทั่วไปอีกสองตัวทำการลบอย่างไร:

http://mssql-to-postgresql.blogspot.com/2007/12/deleting-duplicates-in-postgresql-ms.html


ขอบคุณสำหรับเคล็ดลับ SQL Server ที่นั่นฉันต้องปรับแต่ง SQL ตามบรรทัดเหล่านั้น
Pauk

7

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


ฉันหวังว่าฉันจะไม่ต้องทำแบบนั้นฉันคิดว่าฉันจะต้องเลือก ID ลงในตารางชั่วคราวเนื่องจากความสัมพันธ์ไม่ใช่ผู้ปกครองเด็ก เมื่อแถวจากตารางหนึ่งหายไปจะไม่มีทางรับแถวอื่นได้
Byron Whitlock

3

ในเซิร์ฟเวอร์ SQL ไม่มีวิธีการลบหลายตารางโดยใช้การเข้าร่วม ดังนั้นคุณต้องลบจากลูกก่อนก่อนที่จะลบแบบฟอร์มพาเรนต์


2

นี่เป็นอีกทางเลือกหนึ่งในการลบบันทึกโดยไม่ทิ้งเด็กกำพร้า

ประกาศ @ ตารางผู้ใช้ (keyValue int, someString varchar (10))
แทรกลงใน @user
ค่า (1, '1 ค่า')

แทรกลงใน @user
ค่า (2, '2 ค่า')

แทรกลงใน @user
ค่า (3, '3 ค่า')

Declare @password Table (keyValue int รายละเอียด varchar (10))
แทรกลงใน @password
ค่า (1, '1 รหัสผ่าน')
แทรกลงใน @password
ค่า (2, '2 รหัสผ่าน')
แทรกลงใน @password
ค่า (3, '3 รหัสผ่าน')

        - ก่อนลบ
  เลือก * จาก @password a inner join @user b
                ใน a.keyvalue = b.keyvalue
  เลือก * เป็น #deletedID จาก @user โดยที่ keyvalue = 1 - ใช้งานได้เหมือนกับตัวอย่างเอาต์พุต
  ลบ @user โดยที่ keyvalue = 1
  ลบ @password โดยที่ keyvalue (เลือก keyvalue จาก #deletedid)

  - หลังจากการลบ -
  เลือก * จาก @password a inner join @user b
                ใน a.keyvalue = b.keyvalue


2

ทั้งหมดได้รับการชี้ให้เห็น เพียงแค่ใช้DELETE ON CASCADEบนพาเรนต์tableหรือลบจากchild-tableไฟล์parent.


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

1

ดังที่แอรอนได้ชี้ให้เห็นแล้วคุณสามารถตั้งค่าพฤติกรรมการลบเป็น CASCADE และจะลบบันทึกของเด็กเมื่อบันทึกหลักถูกลบ เว้นแต่คุณต้องการให้เวทมนตร์อื่น ๆ เกิดขึ้น (ซึ่งในกรณีนี้คะแนน 2, 3 ของคำตอบของแอรอนจะเป็นประโยชน์) ฉันไม่เห็นว่าทำไมคุณต้องลบด้วยการรวมภายใน


0

เพื่อสร้างตามคำตอบของ John Gibb สำหรับการลบชุดข้อมูลในสองตารางที่มีความสัมพันธ์ FK:

--*** To delete from tblMain which JOINs to (has a FK of) tblReferredTo's PK  
--       i.e.  ON tblMain.Refer_FK = tblReferredTo.ID
--*** !!! If you're CERTAIN that no other rows anywhere also refer to the 
--      specific rows in tblReferredTo !!!
BEGIN TRAN;

    --*** Keep the ID's from tblReferredTo when we DELETE from tblMain
    DECLARE @tblDeletedRefs TABLE ( ID INT );
    --*** DELETE from the referring table first
    DELETE FROM tblMain 
    OUTPUT DELETED.Refer_FK INTO @tblDeletedRefs  -- doesn't matter that this isn't DISTINCT, the following DELETE still works.
    WHERE ..... -- be careful if filtering, what if other rows 
                --   in tblMain (or elsewhere) also point to the tblReferredTo rows?

    --*** Now we can remove the referred to rows, even though tblMain no longer refers to them.
    DELETE tblReferredTo
    FROM   tblReferredTo INNER JOIN @tblDeletedRefs Removed  
            ON tblReferredTo.ID = Removed.ID;

COMMIT TRAN;

-3
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION

จะไม่ลบตั้งแต่สองตารางขึ้นไปโปรดทำความเข้าใจกับคำถาม
Kamran Shahid

-5

$ SQL = "DELETE FROM basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl ใช้ basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl WHERE b_id= e_id= p_id= a_id= d_id= '" $ ID..' "; อาร์เอส $ = mysqli_query ($ ปรับอากาศ, $ SQL);


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