Es posible eliminar de varias tablas en la misma instrucción SQL?


Es posible eliminar usando instrucciones join para calificar el conjunto a ser eliminado, como lo siguiente:

DELETE J
FROM Users U
inner join LinkingTable J on U.id = J.U_id
inner join Groups G on J.G_id = G.id

WHERE G.Name = 'Whatever'
and U.Name not in ('Exclude list')

Sin embargo, estoy interesado en eliminar ambos lados de los criterios de unión, tanto el registro LinkingTable como el registro de Usuario del que depende. No puedo activar las cascadas porque mi solución es Entity Framework code first y las relaciones bidireccionales crean múltiples rutas en cascada.

Idealmente, me gustaría algo como:

DELETE J, U
FROM Users U
inner join LinkingTable J on U.id = J.U_id
...

Sintácticamente esto no trabajar, pero tengo curiosidad si algo como esto es posible?

Author: Unihedron, 2013-07-09

5 answers

No, tendría que ejecutar varias sentencias.

Debido a que necesita eliminar de dos tablas, considere crear una tabla temporal de los id coincidentes:

SELECT U.Id INTO #RecordsToDelete
FROM Users U
   JOIN LinkingTable J ON U.Id = J.U_Id
...

Y luego eliminar de cada una de las tablas:

DELETE FROM Users 
WHERE Id IN (SELECT Id FROM #RecordsToDelete)

DELETE FROM LinkingTable
WHERE Id IN (SELECT Id FROM #RecordsToDelete)
 34
Author: sgeddes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-09 03:06:17

La forma en que dices es Posible en MY SQL pero no para SQL SERVER

Puede usar la pseudo tabla" deleted " para eliminar los valores de Dos Tablas a la vez como,

 begin transaction;

 declare @deletedIds table ( samcol1 varchar(25) );

 delete #temp1
 output deleted.samcol1 into @deletedIds
 from #temp1 t1
 join #temp2 t2
 on t2.samcol1 = t1.samcol1

 delete #temp2
 from #temp2 t2
 join @deletedIds d
 on d.samcol1 = t2.samcol1;

 commit transaction;

Para una breve explicación, puede echar un vistazo a este Enlace

Y para Conocer el Uso de la Tabla Eliminada puede seguir esta Utilizando las Tablas insertadas y eliminadas

 3
Author: Rajesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:41

La única manera que se me ocurre es romper lógicamente las claves foráneas bidireccionales de una manera procedural.

Este enfoque puede tener un gran impacto en el lado de su aplicación si no tiene algunas banderas para visualization estado o status

Algo así como

  1. INSERT filas ficticias no visibles para los usuarios (con algo como Id = -1 para valores ficticios)
  2. Agregue a LinkingTable una columna alternativa para apuntar de nuevo a Users, la llamaré U_ComesFrom

    ALTER TABLE LinkingTagble ADD U_ComesFrom_U_id INT DEFAULT (-1)

  3. Añadir FOREIGN KEY con NOCHECK

    ALTER TABLE LinkingTable WITH NOCHECK
    CLAVE FORÁNEA (U_ComesFrom_U_id)
    REFERENCIAS Usuarios (Id);

  4. Añadir a la columna Users

    ALTER TABLE Users ADD MarkedForDeletion BIT NOT NULL DEFAULT (0)

Entonces su SQL se vería como

BEGIN TRANSACTION
    UPDATE J
    SET U_Comes_From_U_id = U_ID, U_id = -1 -- or some N/R value that you define in Users
    FROM Users U
    inner join LinkingTable J on U.id = J.U_id
    inner join Groups G on J.G_id = G.id
    WHERE G.Name = 'Whatever'
    and U.Name not in ('Exclude list')

    UPDATE U
    SET MarkedForDeletion = 1
    FROM Users
    inner join LinkingTable J on U.id = J.U_ComesFrom_U_id 
    WHERE U_id > 0

    DELETE FROM LinkingTable 
    WHERE U_ComesFrom_U_id > 0

    DELETE FROM Users
    WHERE MarkedForDeletion = 1

COMMIT

Este enfoque afectaría el rendimiento ya que cada la transacción sería al menos 4 operaciones DML por claves bidireccionales.

 2
Author: Luis LL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-09 05:33:01

Use TRY CATCH con Transaction

BEGIN TRANSACTION
BEGIN TRY
    DELETE from A WHERE id=1

    DELETE FROM b WHERE id=1

    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
END CATCH

O también puede utilizar el procedimiento de la tienda para el mismo Usando El Procedimiento Almacenado Con La Transacción:

 1
Author: uma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-09 05:56:46

Si está creando la clave foránea a través de T-SQL, debe agregar la opción ON DELETE CASCADE a la clave foránea:

Code Snippet 

ALTER TABLE <tablename>
ADD CONSTRAINT <constraintname> FOREIGN KEY (<columnname(s)>)
REFERENCES <referencedtablename> (<columnname(s)>)

ON DELETE CASCADE;
 1
Author: Nagu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-31 09:29:40