Come posso eliminare da più tabelle utilizzando INNER JOIN in SQL server


117

In MySQL puoi usare la sintassi

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

Come faccio a fare la stessa cosa in SQL Server?

Risposte:


119

È possibile sfruttare la pseudo tabella "cancellata" in questo esempio. Qualcosa di simile a:

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;

Ovviamente puoi fare un 'output cancellato'. anche sulla seconda eliminazione, se avevi bisogno di qualcosa a cui partecipare per il terzo tavolo.

Come nota a margine, puoi anche inserire. * Su un'istruzione insert, ed entrambi inseriti. * E cancellati. * Su un'istruzione update.

EDIT: Inoltre, hai considerato l'aggiunta di un trigger su table1 per eliminare da table2 + 3? Sarai all'interno di una transazione implicita e avrai a disposizione anche le pseudo-tabelle "inserite. " E "cancellate. ".


2
È meglio semplicemente DELETE FROM table1 WHERE id = x e quindi eliminare dalla tabella successiva invece di utilizzare inner join e passare attraverso tutto questo testo extra ?? Fondamentalmente, saltando l'unione interna ho solo bisogno di 2 semplici query ... O questo metodo è più efficiente?
Colandus

Penso che dipenda da quanto sia complicata la tua clausola Where. Per uno complicato, questo sarebbe meglio perché accade solo una volta. Ma per una clausola where più semplice che influisce su molte righe, la tua proposta sarebbe probabilmente più efficiente poiché non deve contenere molti ID in una variabile di tabella.
John Gibb

@ JohnGibb, come funziona questa risposta? Puoi spiegare questa risposta in modo che uno sviluppatore MySQL possa capirla?
Pacerier

@Pacerier Non ho molta familiarità con MySQL. L'idea è che la prima eliminazione venga eliminata solo dalla tabella1, ma salvi gli ID eliminati in una variabile. Le due istruzioni successive utilizzano quella variabile per eliminare le righe associate dalla tabella 2 e dalla tabella 3.
John Gibb

@ JohnGibb, ora è chiaro. Dovresti includerlo nella risposta.
Pacerier

15
  1. È sempre possibile impostare eliminazioni a cascata sulle relazioni delle tabelle.

  2. È possibile incapsulare più eliminazioni in una stored procedure.

  3. È possibile utilizzare una transazione per garantire un'unità di lavoro.


3
Sicuramente possibile eliminare su un'istruzione di join, devo solo eliminare da più di una tabella alla volta.
Byron Whitlock,

Risposta sbagliata, i join possono essere utilizzati con delete
rboarman

ad 1.) Non è vero, potrebbe non essere sempre possibile. Ci sono alcuni scenari in cui non è possibile impostare eliminazioni a cascata, ad esempio cicli o più percorsi a cascata. (vedi stackoverflow.com/a/3548225/108374 per esempio)
Tom Pažourek

15

È possibile utilizzare la sintassi JOIN nella clausola FROM in DELETE in SQL Server, ma si elimina comunque solo dalla prima tabella e la sua estensione Transact-SQL proprietaria è alternativa alla sottoquery.

Dall'esempio qui :

 -- 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
Esempio 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

Esempio per eliminare alcuni record dalla tabella principale e i record corrispondenti da due tabelle di dettaglio:

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
Potresti usare SELECT INTO #DeleteIdsinvece di CREATE TABLE 'DeleteIdsseguito da INSERT INTO 'DeleteIds...?
Caltor

9

Mi chiedevo solo ... è davvero possibile in MySQL? cancellerà t1 e t2? o ho semplicemente frainteso la domanda.

Ma se vuoi solo eliminare table1 con più condizioni di join, non creare alias per la tabella che desideri eliminare

Questo:

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

dovrebbe essere scritto in questo modo per funzionare in MSSQL:

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

per contrastare come gli altri due RDBMS comuni eseguono un'operazione di cancellazione:

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


Grazie per il suggerimento di SQL Server, ho dovuto modificare l'SQL in questo modo.
Pauk

7

Fondamentalmente, no, devi fare tre dichiarazioni di cancellazione in una transazione, prima i bambini e poi i genitori. L'impostazione delle eliminazioni a cascata è una buona idea se questa non è una cosa una tantum e la sua esistenza non è in conflitto con nessuna configurazione di trigger esistente.


Speravo di non doverlo fare, suppongo che dovrò selezionare gli ID in una tabella temporanea poiché la relazione non è genitore-figlio. una volta che le righe di una tabella sono sparite, non è possibile ottenere le altre righe.
Byron Whitlock

3

In SQL Server non è possibile eliminare più tabelle utilizzando join. Quindi devi eliminare da figlio prima di eliminare il genitore dal modulo.


2

Questo è un modo alternativo per eliminare i record senza lasciare orfani.

Dichiara @user Table (keyValue int, someString varchar (10))
inserire in @user
valori (1, '1 valore')

inserire in @user
valori (2, '2 valore')

inserire in @user
valori (3, '3 valore')

Dichiara @password Table (keyValue int, dettagli varchar (10))
inserire in @password
valori (1, '1 password')
inserire in @password
valori (2, '2 Password')
inserire in @password
valori (3, '3 Password')

        - prima della cancellazione
  seleziona * da @password a inner join @user b
                su a.keyvalue = b.keyvalue
  seleziona * in #deletedID da @user dove keyvalue = 1 - funziona come l'esempio di output
  elimina @user dove keyvalue = 1
  elimina @password dove keyvalue in (seleziona keyvalue da #deletedid)

  --Dopo la cancellazione--
  seleziona * da @password a inner join @user b
                su a.keyvalue = b.keyvalue


2

Tutto è stato sottolineato. Basta usare DELETE ON CASCADEsul genitore tableo eliminare da child-tablea parent.


Cosa intendi per cancellare dalla tabella figlia al genitore? intendi usando la tecnica dei join come quella mostrata in questione o le risposte di cui sopra?
Imran Faruqi

1

Come Aaron ha già sottolineato, puoi impostare il comportamento di eliminazione su CASCADE e questo eliminerà i record figli quando viene eliminato un record padre. A meno che tu non voglia che accada qualche altra magia (nel qual caso i punti 2 e 3 della risposta di Aaron sarebbero utili), non vedo perché dovresti eliminare con i join interni.


0

Per basarsi sulla risposta di John Gibb, per l'eliminazione di un set di dati in due tabelle con una relazione 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

non cancellerà da due o più tabelle. Si prega di comprendere la domanda
Kamran Shahid

-5

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


Correggi la formattazione e fornisci una breve descrizione del motivo per cui il codice funziona.
Bryan Herbst
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.