¿Cómo elimino de varias tablas usando INNER JOIN en SQL Server?

117

En MySQL puedes usar la sintaxis

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

¿Cómo hago lo mismo en SQL Server?

Byron Whitlock
fuente

Respuestas:

119

Puede aprovechar la pseudotabla "eliminada" en este ejemplo. Algo como:

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;

Obviamente, puede hacer una 'salida eliminada'. en la segunda eliminación también, si necesita algo para unirse a la tercera mesa.

Como nota al margen, también puede insertar. * En una declaración de inserción, y tanto insertar. * Como eliminado. * En una declaración de actualización.

EDITAR: Además, ¿ha considerado agregar un activador en la tabla1 para eliminar de la tabla2 + 3? Estará dentro de una transacción implícita y también tendrá disponibles las pseudo-tablas "insertadas " y "eliminadas ".

John Gibb
fuente
2
¿Es mejor simplemente ELIMINAR DE la tabla1 DONDE id = x y luego eliminar de la siguiente tabla en lugar de usar la combinación interna y revisar todo este texto adicional? Básicamente, omitiendo la combinación interna, solo necesito 2 consultas simples ... ¿O es este método más eficiente?
Colandus
Creo que depende de lo complicada que sea la cláusula where. Para uno complicado, esto sería mejor porque solo ocurre una vez. Pero para una cláusula where más simple que afecta a muchas filas, su propuesta probablemente sería más eficiente ya que no tiene que contener muchos identificadores en una variable de tabla.
John Gibb
@JohnGibb, ¿cómo funciona esta respuesta? ¿Puede explicar esta respuesta para que un desarrollador de MySQL pueda entenderla?
Pacerier
@Pacerier No estoy muy familiarizado con MySQL. La idea es que la primera eliminación solo se elimina de la tabla1, pero se guardan las ID que se eliminaron en una variable. Las siguientes dos declaraciones cómo usan esa variable para eliminar las filas asociadas de table2 y table 3.
John Gibb
@JohnGibb, eso está claro. Deberías incluir eso en la respuesta.
Pacerier
15
  1. Siempre puede configurar eliminaciones en cascada en las relaciones de las tablas.

  2. Puede encapsular las múltiples eliminaciones en un procedimiento almacenado.

  3. Puede utilizar una transacción para garantizar una unidad de trabajo.

Aaron Daniels
fuente
3
Definitivamente es posible eliminar en una declaración de combinación, solo quiero eliminar de más de una tabla a la vez.
Byron Whitlock
Respuesta incorrecta, las uniones se pueden usar con eliminar
rboarman
ad 1.) Eso no es cierto, puede que no siempre sea posible. Hay algunos escenarios en los que no puede configurar eliminaciones en cascada, por ejemplo, ciclos o múltiples rutas en cascada. (ver stackoverflow.com/a/3548225/108374 por ejemplo)
Tom Pažourek
15

Puede usar la sintaxis JOIN en la cláusula FROM en DELETE en SQL Server, pero aún así elimina solo de la primera tabla y su extensión Transact-SQL patentada, que es alternativa a la subconsulta.

De ejemplo aquí :

 -- 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;
el mejor chef
fuente
3
Ejemplo D: ELIMINAR DE Sales.SalesPersonQuotaHistory DE Sales.SalesPersonQuotaHistory AS spqh INNER JOIN Sales.SalesPerson AS sp en spqh.BusinessEntityID = sp.BusinessEntityID DONDE sp.SalesYTD> 2500000.00;
Mark A
11

Ejemplo para eliminar algunos registros de la tabla maestra y los registros correspondientes de dos tablas de detalle:

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
fuente
1
¿Podrías usar en SELECT INTO #DeleteIdslugar de CREATE TABLE 'DeleteIdsseguido de INSERT INTO 'DeleteIds...?
Caltor
9

Me pregunto ... ¿es eso realmente posible en MySQL? eliminará t1 y t2? o simplemente entendí mal la pregunta.

Pero si solo desea eliminar table1 con múltiples condiciones de combinación, simplemente no alias la tabla que desea eliminar

esta:

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

debe escribirse así para que funcione en MSSQL:

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

para contrastar cómo los otros dos RDBMS comunes realizan una operación de eliminación:

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

Michael Buen
fuente
Gracias por la sugerencia de SQL Server, tuve que modificar el SQL en ese sentido.
Pauk
7

Básicamente, no, tiene que hacer tres declaraciones de eliminación en una transacción, los niños primero y luego los padres. La configuración de eliminaciones en cascada es una buena idea si esto no es algo único y su existencia no entrará en conflicto con ninguna configuración de disparador existente.

Yishai
fuente
Tenía la esperanza de no tener que hacer eso, supongo que tendré que seleccionar los ID en una tabla temporal ya que la relación no es de padres e hijos. una vez que las filas de una tabla desaparecen, no hay forma de obtener las otras filas.
Byron Whitlock
3

En el servidor SQL no hay forma de eliminar varias tablas usando join. Por lo tanto, primero debe eliminar del niño antes de eliminar el formulario principal.

minúsculo
fuente
2

Esta es una forma alternativa de eliminar registros sin dejar huérfanos.

Declare @user Table (keyValue int, someString varchar (10))
insertar en @user
valores (1, '1 valor')

insertar en @user
valores (2, 'valor 2')

insertar en @user
valores (3, 'valor 3')

Declare @password Table (keyValue int, detalles varchar (10))
insertar en @password
valores (1, '1 contraseña')
insertar en @password
valores (2, '2 Contraseña')
insertar en @password
valores (3, '3 Contraseña')

        - antes de la eliminación
  seleccione * de @password a combinación interna @user b
                en a.keyvalue = b.keyvalue
  seleccione * en #deletedID de @user donde keyvalue = 1 - esto funciona como el ejemplo de salida
  eliminar @user donde keyvalue = 1
  eliminar @password donde keyvalue in (seleccione keyvalue de #deletedid)

  --Después de la eliminación--
  seleccione * de @password a combinación interna @user b
                en a.keyvalue = b.keyvalue

oculto
fuente
2

Todo ha sido señalado. Simplemente use DELETE ON CASCADEen el padre tableo elimínelo del child-tableal parent.

Kayode
fuente
¿Qué quiere decir con eliminar de la tabla secundaria a la principal? ¿Te refieres al uso de la técnica de combinaciones como la que se muestra en la pregunta o las respuestas antes mencionadas?
Imran Faruqi
1

Como Aaron ya ha señalado, puede establecer el comportamiento de eliminación en CASCADA y eso eliminará los registros secundarios cuando se elimine un registro principal. A menos que desee que suceda algún otro tipo de magia (en cuyo caso los puntos 2, 3 de la respuesta de Aaron serían útiles), no veo por qué necesitaría eliminar con combinaciones internas.

Peter Perháč
fuente
0

Para construir sobre la respuesta de John Gibb, para eliminar un conjunto de datos en dos tablas con una relación 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
fuente
-3
DELETE     TABLE1 LIN
FROM TABLE1 LIN
INNER JOIN TABLE2 LCS ON  CONDITION
WHERE CONDITION
ARUN
fuente
no se eliminará de dos o más tablas. Por favor, comprenda la pregunta
Kamran Shahid
-5

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

Dharmesh
fuente
Corrija el formato y proporcione una breve descripción de por qué funciona su código.
Bryan Herbst