Wie lösche ich mit INNER JOIN in SQL Server aus mehreren Tabellen?

117

In MySQL können Sie die Syntax verwenden

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

Wie mache ich dasselbe in SQL Server?

Byron Whitlock
quelle

Antworten:

119

In diesem Beispiel können Sie die "gelöschte" Pseudotabelle nutzen. Etwas wie:

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;

Natürlich können Sie eine "Ausgabe gelöscht" ausführen. auch beim zweiten Löschen, wenn Sie etwas für die dritte Tabelle benötigen.

Als Randnotiz können Sie auch einfügen. * In eine Einfügeanweisung und beide eingefügt. * Und gelöscht. * In eine Aktualisierungsanweisung.

EDIT: Haben Sie auch darüber nachgedacht, einen Trigger für Tabelle1 hinzuzufügen, um ihn aus Tabelle2 + 3 zu löschen? Sie befinden sich innerhalb einer impliziten Transaktion und haben auch die Pseudotabellen "eingefügt " und "gelöscht " verfügbar.

John Gibb
quelle
2
Ist es besser, einfach AUS table1 WHERE id = x zu löschen und dann aus der nächsten Tabelle zu löschen, anstatt den inneren Join zu verwenden und den gesamten zusätzlichen Text durchzugehen? Wenn ich den inneren Join überspringe, brauche ich nur zwei einfache Abfragen ... Oder ist diese Methode effizienter?
Colandus
Ich denke, es hängt davon ab, wie kompliziert Ihre where-Klausel ist. Für einen komplizierten wäre dies besser, da es nur einmal vorkommt. Für eine einfachere where-Klausel, die viele Zeilen betrifft, wäre Ihr Vorschlag wahrscheinlich effizienter, da er nicht viele IDs in einer Tabellenvariablen enthalten muss.
John Gibb
@ JohnGibb, Wie funktioniert diese Antwort? Können Sie diese Antwort erklären, damit ein MySQL-Entwickler sie verstehen kann?
Pacerier
@ Pacerier Ich bin nicht sehr vertraut mit MySQL. Die Idee ist, dass beim ersten Löschen nur aus Tabelle1 gelöscht wird, aber die gelöschten IDs in einer Variablen gespeichert werden. Die folgenden zwei Anweisungen, wie diese Variable verwendet wird, um die zugehörigen Zeilen aus Tabelle2 und Tabelle 3 zu löschen.
John Gibb
@JohnGibb, nun , das ist klar. Sie sollten das in die Antwort aufnehmen.
Pacerier
15
  1. Sie können jederzeit kaskadierende Löschvorgänge für die Beziehungen der Tabellen einrichten.

  2. Sie können die mehreren Löschvorgänge in einer gespeicherten Prozedur kapseln.

  3. Sie können eine Transaktion verwenden, um eine Arbeitseinheit sicherzustellen.

Aaron Daniels
quelle
3
Es ist definitiv möglich, eine Join-Anweisung zu löschen. Ich möchte nur aus mehr als einer Tabelle gleichzeitig löschen.
Byron Whitlock
Falsche Antwort, Joins können mit delete
rboarman
ad 1.) Das ist nicht wahr, es ist möglicherweise nicht immer möglich. Es gibt einige Szenarien, in denen Sie keine kaskadierenden Löschvorgänge einrichten können, z. B. Zyklen oder mehrere Kaskadenpfade. (Siehe zum Beispiel stackoverflow.com/a/3548225/108374 )
Tom Pažourek
15

Sie können die JOIN-Syntax in der FROM-Klausel in DELETE in SQL Server verwenden, aber Sie löschen immer noch nur aus der ersten Tabelle und der proprietären Transact-SQL-Erweiterung, die eine Alternative zur Unterabfrage darstellt.

Aus dem Beispiel hier :

 -- 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;
Spitzenkoch
quelle
3
Beispiel 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;
Markieren Sie A
11

Beispiel zum Löschen einiger Datensätze aus der Mastertabelle und entsprechender Datensätze aus zwei Detailtabellen:

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
quelle
1
Könnten Sie verwenden, SELECT INTO #DeleteIdsanstatt CREATE TABLE 'DeleteIdsgefolgt von INSERT INTO 'DeleteIds...?
Caltor
9

Ich frage mich nur ... ist das in MySQL wirklich möglich? es wird t1 und t2 löschen? oder ich habe die Frage einfach falsch verstanden.

Wenn Sie jedoch nur Tabelle1 mit mehreren Verknüpfungsbedingungen löschen möchten, geben Sie der zu löschenden Tabelle keinen Alias

Dies:

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

sollte so geschrieben werden, um in MSSQL zu funktionieren:

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

im Gegensatz dazu, wie die beiden anderen gängigen RDBMS einen Löschvorgang ausführen:

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

Michael Buen
quelle
Vielen Dank für den SQL Server-Tipp, ich musste das SQL in diese Richtung optimieren.
Pauk
7

Grundsätzlich müssen Sie in einer Transaktion nicht drei Löschanweisungen machen, zuerst Kinder und dann Eltern. Das Einrichten von kaskadierenden Löschvorgängen ist eine gute Idee, wenn dies keine einmalige Sache ist und ihre Existenz nicht mit einem vorhandenen Trigger-Setup in Konflikt steht.

Yishai
quelle
Ich hatte gehofft, dass ich das nicht tun musste, ich nehme an, ich muss die IDs in einer temporären Tabelle auswählen, da die Beziehung keine Eltern-Kind-Beziehung ist. Sobald die Zeilen einer Tabelle verschwunden sind, können die anderen Zeilen nicht mehr abgerufen werden.
Byron Whitlock
3

In SQL Server gibt es keine Möglichkeit, mehrere Tabellen mithilfe von Join zu löschen. Sie müssen also zuerst das untergeordnete Element löschen, bevor Sie das übergeordnete Formular löschen können.

sehr klein
quelle
2

Dies ist eine alternative Möglichkeit, Datensätze zu löschen, ohne Waisen zu hinterlassen.

Deklarieren Sie die @ user-Tabelle (keyValue int, someString varchar (10)).
in @user einfügen
Werte (1, '1 Wert')

in @user einfügen
Werte (2, '2 Wert')

in @user einfügen
Werte (3, '3 Wert')

Deklarieren Sie die @ Passwort-Tabelle (keyValue int, details varchar (10))
in @password einfügen
Werte (1, '1 Passwort')
in @password einfügen
Werte (2, '2 Passwort')
in @password einfügen
Werte (3, '3 Passwort')

        --vor dem Löschen
  Wählen Sie * aus @password a inner join @user b
                on a.keyvalue = b.keyvalue
  Wählen Sie * in #deletedID von @user aus, wobei keyvalue = 1 ist - dies funktioniert wie im Ausgabebeispiel
  lösche @user wobei keyvalue = 1 ist
  lösche @password wo Schlüsselwert in (wähle Schlüsselwert aus #deletedid)

  --Nach dem Löschen--
  Wählen Sie * aus @password a inner join @user b
                on a.keyvalue = b.keyvalue

versteckt
quelle
2

Alles wurde darauf hingewiesen. Verwenden Sie einfach entweder DELETE ON CASCADEauf dem übergeordneten tableoder löschen Sie von der child-tableauf die parent.

Kayode
quelle
Was meinst du mit Löschen von der untergeordneten Tabelle zum übergeordneten? Meinen Sie damit die Verwendung von Joins-Techniken wie der in der Frage gezeigten oder den oben genannten Antworten?
Imran Faruqi
1

Wie Aaron bereits betont hat, können Sie das Löschverhalten auf CASCADE setzen. Dadurch werden untergeordnete Datensätze gelöscht, wenn ein übergeordneter Datensatz gelöscht wird. Wenn Sie nicht möchten, dass irgendeine andere Magie geschieht (in diesem Fall wären die Punkte 2, 3 von Aarons Antwort nützlich), verstehe ich nicht, warum Sie mit inneren Verknüpfungen löschen müssen.

Peter Perháč
quelle
0

Um auf John Gibbs Antwort aufzubauen und einen Datensatz in zwei Tabellen mit einer FK-Beziehung zu löschen:

--*** 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
quelle
-3
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION
ARUN
quelle
Es wird nicht aus zwei oder mehr Tabellen gelöscht. Bitte verstehen Sie die Frage
Kamran Shahid
-5

$ sql = "DELETE FROM basic_tbl, education_tbl, personal_tbl, address_tbl, weiter department_tbl verwenden basic_tbl, education_tbl, personal_tbl, address_tbl, department_tbl WO b_id= e_id= p_id= a_id= d_id= '" $ id.. "‘ „; $ rs = mysqli_query ($ con, $ sql);

Dharmesh
quelle
Bitte korrigieren Sie Ihre Formatierung und beschreiben Sie kurz, warum Ihr Code funktioniert.
Bryan Herbst