Bagaimana cara menghapus dari beberapa tabel menggunakan INNER JOIN di SQL server

117

Di MySQL Anda dapat menggunakan sintaks

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

Bagaimana cara melakukan hal yang sama di SQL Server?

Byron Whitlock
sumber

Jawaban:

119

Anda dapat memanfaatkan tabel semu yang "dihapus" dalam contoh ini. Sesuatu seperti:

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;

Jelas Anda bisa melakukan 'keluaran dihapus.' pada hapus kedua juga, jika Anda membutuhkan sesuatu untuk digabungkan untuk tabel ketiga.

Sebagai catatan tambahan, Anda juga dapat melakukan penyisipan. * Pada pernyataan penyisipan, dan keduanya disisipkan. * Dan dihapus. * Pada pernyataan pembaruan.

EDIT: Juga, apakah Anda mempertimbangkan untuk menambahkan pemicu pada table1 untuk menghapus dari table2 + 3? Anda akan berada di dalam transaksi implisit, dan juga akan mendapatkan pseudo-tabel "dimasukkan " dan "dihapus ".

John Gibb
sumber
2
Apakah lebih baik hanya MENGHAPUS DARI tabel1 WHERE id = x dan kemudian menghapus dari tabel berikutnya daripada menggunakan gabungan dalam dan melalui semua teks tambahan ini ?? Pada dasarnya, melewatkan inner join saya hanya perlu 2 query sederhana .... Atau metode ini lebih efisien?
Colandus
Saya pikir itu tergantung pada seberapa rumit klausa where Anda. Untuk yang rumit, ini akan lebih baik karena hanya terjadi sekali. Namun untuk klausa sederhana yang memengaruhi banyak baris, proposal Anda mungkin akan lebih efisien karena tidak harus memiliki banyak id dalam variabel tabel.
John Gibb
@JohnGibb, Bagaimana cara kerja jawaban ini? Bisakah Anda menjelaskan jawaban ini agar pengembang MySQL dapat memahaminya?
Pacerier
@Pacerier Saya tidak terlalu akrab dengan MySQL. Idenya adalah bahwa penghapusan pertama hanya menghapus dari tabel1, tetapi ini menyimpan ID yang telah dihapus ke dalam variabel. Dua pernyataan berikutnya bagaimana menggunakan variabel itu untuk menghapus baris terkait dari tabel2 dan tabel 3.
John Gibb
@JohnGibb, Sekarang sudah jelas. Anda harus memasukkan itu dalam jawaban.
Pacerier
15
  1. Anda selalu bisa menyiapkan penghapusan berjenjang pada hubungan tabel.

  2. Anda dapat merangkum beberapa penghapusan dalam satu prosedur yang tersimpan.

  3. Anda dapat menggunakan transaksi untuk memastikan satu unit kerja.

Aaron Daniels
sumber
3
Sangat mungkin untuk menghapus pada pernyataan bergabung, saya hanya ingin menghapus dari lebih dari satu tabel pada satu waktu.
Byron Whitlock
Jawaban yang salah, join dapat digunakan dengan delete
rboarman
ad 1.) Itu tidak benar, itu mungkin tidak selalu mungkin. Ada beberapa skenario di mana Anda tidak dapat mengatur penghapusan bertingkat, misalnya siklus atau beberapa jalur kaskade. (lihat stackoverflow.com/a/3548225/108374 misalnya)
Tom Pažourek
15

Anda dapat menggunakan sintaks JOIN di klausa FROM di DELETE di SQL Server tetapi Anda masih menghapus dari tabel pertama saja dan ekstensi Transact-SQL miliknya yang merupakan alternatif untuk sub-kueri.

Dari contoh di sini :

 -- 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;
topchef
sumber
3
Contoh D: HAPUS DARI Sales.SalesPersonQuotaHistory FROM Sales.SalesPersonQuotaHistory SEBAGAI spqh INNER JOIN Sales.SalesPerson SEBAGAI sp ON spqh.BusinessEntityID = sp.BusinessEntityID WHERE sp.SalesYTD> 2500000.00;
Tandai A
11

Contoh untuk menghapus beberapa rekaman dari tabel master dan rekaman terkait dari dua tabel detail:

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
Pavel Hodek
sumber
1
Bisakah Anda menggunakan SELECT INTO #DeleteIdsalih-alih CREATE TABLE 'DeleteIdsdiikuti oleh INSERT INTO 'DeleteIds...?
Caltor
9

Hanya ingin tahu .. apakah itu mungkin di MySQL? itu akan menghapus t1 dan t2? atau saya hanya salah memahami pertanyaan itu.

Tetapi jika Anda hanya ingin menghapus tabel1 dengan beberapa kondisi penggabungan, jangan alias tabel yang ingin Anda hapus

ini:

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

harus ditulis seperti ini untuk bekerja di MSSQL:

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

untuk membedakan bagaimana dua RDBMS umum lainnya melakukan operasi penghapusan:

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

Michael Buen
sumber
Terima kasih atas tip SQL Server di sana, saya harus mengubah SQL di sepanjang baris itu.
Pauk
7

Pada dasarnya, tidak, Anda harus membuat tiga pernyataan hapus dalam transaksi, anak-anak terlebih dahulu dan kemudian orang tua. Menyiapkan cascading delete adalah ide yang bagus jika ini bukan hal yang hanya terjadi satu kali dan keberadaannya tidak akan bertentangan dengan pengaturan pemicu yang ada.

Yishai
sumber
Saya berharap saya tidak perlu melakukan itu, saya kira saya harus memilih ID ke tabel temp karena hubungannya bukan hubungan orang tua. setelah baris dari satu tabel hilang, tidak ada cara untuk mendapatkan baris lainnya.
Byron Whitlock
3

Di SQL server, tidak ada cara untuk menghapus beberapa tabel menggunakan join. Jadi Anda harus menghapus dari anak terlebih dahulu sebelum menghapus formulir induk.

mungil
sumber
2

Ini adalah cara alternatif untuk menghapus catatan tanpa meninggalkan yatim piatu.

Deklarasikan Tabel @user (keyValue int, someString varchar (10))
masukkan ke @user
nilai (1, '1 nilai')

masukkan ke @user
nilai (2, '2 nilai')

masukkan ke @user
nilai (3, '3 nilai')

Deklarasikan Tabel @password (keyValue int, details varchar (10))
masukkan ke @password
nilai (1, '1 Password')
masukkan ke @password
nilai (2, '2 Password')
masukkan ke @password
nilai (3, '3 Kata Sandi')

        --sebelum penghapusan
  pilih * dari @password a inner join @user b
                di a.keyvalue = b.keyvalue
  pilih * ke #deletedID dari @user di mana keyvalue = 1 - ini berfungsi seperti contoh keluaran
  hapus @user dimana keyvalue = 1
  hapus @ kata sandi di mana nilai kunci masuk (pilih nilai kunci dari #deletedid)

  --Setelah penghapusan--
  pilih * dari @password a inner join @user b
                di a.keyvalue = b.keyvalue

tersembunyi
sumber
2

Semua telah ditunjukkan. Cukup gunakan salah satu DELETE ON CASCADEdari induknya tableatau hapus dari child-tableke parent.

kayode
sumber
Apa yang Anda maksud dengan menghapus dari tabel anak ke induk? yang Anda maksud dengan menggunakan teknik penggabungan seperti yang ditunjukkan dalam pertanyaan atau jawaban yang disebutkan di atas?
Imran Faruqi
1

Seperti yang telah ditunjukkan oleh Aaron, Anda dapat mengatur perilaku delete ke CASCADE dan itu akan menghapus rekaman anak ketika rekaman induk dihapus. Kecuali jika Anda ingin keajaiban lain terjadi (dalam hal ini poin 2, 3 dari balasan Aaron akan berguna), saya tidak mengerti mengapa Anda perlu menghapus dengan gabungan dalam.

Peter Perháč
sumber
0

Untuk mengembangkan jawaban John Gibb, untuk menghapus sekumpulan data dalam dua tabel dengan hubungan 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;
AjV Jsy
sumber
-3
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION
ARUN
sumber
itu tidak akan menghapus dari dua atau lebih tabel.Harap mengerti pertanyaannya
Kamran Shahid
-5

$ sql = "DELETE FROM basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl MENGGUNAKAN basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl MANA b_id= e_id= p_id= a_id= d_id= '" $ id.. "' "; $ rs = mysqli_query ($ con, $ sql);

Dharmesh
sumber
Perbaiki pemformatan Anda dan berikan penjelasan singkat tentang mengapa kode Anda berfungsi.
Bryan Herbst