T-SQL: selección de filas para eliminar mediante combinaciones

494

Guión:

Digamos que tengo dos tablas, TableA y TableB. La clave principal de TableB es una sola columna (BId), y es una columna de clave externa en TableA.

En mi situación, quiero eliminar todas las filas en la Tabla A que están vinculadas con filas específicas en la Tabla B: ¿Puedo hacerlo mediante uniones? ¿Eliminar todas las filas que se extraen de las uniones?

DELETE FROM TableA 
FROM
   TableA a
   INNER JOIN TableB b
      ON b.BId = a.BId
      AND [my filter condition]

O me veo obligado a hacer esto:

DELETE FROM TableA
WHERE
   BId IN (SELECT BId FROM TableB WHERE [my filter condition])

La razón por la que pregunto es que me parece que la primera opción sería mucho más eficiente cuando se trata de tablas más grandes.

¡Gracias!

Juan
fuente

Respuestas:

723
DELETE TableA
FROM   TableA a
       INNER JOIN TableB b
               ON b.Bid = a.Bid
                  AND [my filter condition] 

Deberia trabajar

TheTXI
fuente
1
Usé Y [mi condición de filtro] en la unión en lugar de una cláusula Where. Me imagino que ambos funcionarían, pero la condición del filtro en la unión limitará los resultados de la unión.
TheTXI el
10
Una pregunta. ¿Por qué necesitamos escribir 'DELETE TableA FROM' en lugar de 'DELETE FROM'? Veo que funciona solo en este caso, pero ¿por qué?
LaBracca
66
Creo que porque tienes que indicar de qué tabla eliminar registros. Acabo de ejecutar una consulta con la sintaxis DELETE TableA, TableB ...y eso realmente eliminó los registros relevantes de ambos. Agradable.
Andrew
1
En PostgreSQL, la sintaxis con join no funciona, pero es posible usar la palabra clave "using". DELETE from TableA a using TableB b where b.Bid = a.Bid and [my filter condition]
bartolo-otrit
8
En MySQL obtendría un error "Tabla desconocida 'TableA' en MULTI DELETE" y eso se debe a que declaró un alias para TableA (a). Pequeño ajuste:DELETE a FROM TableA a INNER JOIN TableB b on b.Bid = a.Bid and [my filter condition]
masam
260

Usaría esta sintaxis

Delete a 
from TableA a
Inner Join TableB b
on  a.BId = b.BId
WHERE [filter condition]
cmsjr
fuente
77
Prefiero esta sintaxis también, parece tener un poco más de sentido lógicamente lo que está sucediendo. Además, sé que puede usar este mismo tipo de sintaxis para una ACTUALIZACIÓN.
Adam Nofsinger
También lo prefiero porque la ubicación del alias de la tabla después de DELETE siempre me ha parecido más intuitiva en cuanto a lo que se está eliminando.
Jagd
14
De hecho, esto también es preferido para mí. Específicamente en los casos en los que necesito unirme en la misma tabla (por ejemplo, para eliminar registros duplicados). En ese caso, necesito usar un alias para el "lado" del que estoy borrando y esta sintaxis deja muy claro que estoy borrando del alias duplicado.
Chris Simmons
29

Sí tu puedes. Ejemplo:

DELETE TableA 
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]
Diadistis
fuente
8
Prefiero referirme a la tabla en la primera línea por su alias. Es decir, "Eliminar a" en lugar de "Eliminar Tabla A". En el caso en el que se une a la tabla consigo mismo, deja en claro de qué lado desea eliminar.
Jeremy Stein
10

Estaba tratando de hacer esto con una base de datos de acceso y descubrí que necesitaba usar un. * Justo después de la eliminación.

DELETE a.*
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]
Tony Emrud
fuente
De rechazado edición pendiente: "La propiedad registros únicos tiene que ser establecido en sí, de lo contrario no funcionará (. Support.microsoft.com/kb/240098 )"
StuperUser
8

Es casi lo mismo en MySQL , pero debe usar el alias de la tabla justo después de la palabra "DELETE":

DELETE a
FROM TableA AS a
INNER JOIN TableB AS b
ON a.BId = b.BId
WHERE [filter condition]
Michael Butler
fuente
2

La sintaxis anterior no funciona en Interbase 2007. En cambio, tuve que usar algo como:

DELETE FROM TableA a WHERE [filter condition on TableA] 
  AND (a.BId IN (SELECT a.BId FROM TableB b JOIN TableA a 
                 ON a.BId = b.BId 
                 WHERE [filter condition on TableB]))

(Nota: Interbase no admite la palabra clave AS para alias)

DavidJ
fuente
2

Estoy usando esto

DELETE TableA 
FROM TableA a
INNER JOIN
TableB b on b.Bid = a.Bid
AND [condition]

y la forma @TheTXI es suficiente, pero leí respuestas y comentarios y descubrí que una cosa que debe responderse es usar la condición en la cláusula WHERE o como condición de unión. Así que decidí probarlo y escribir un fragmento, pero no encontré una diferencia significativa entre ellos. Puede ver el script sql aquí y el punto importante es que preferí escribirlo como commnet porque esto no es una respuesta exacta pero es grande y no se puede poner en los comentarios, por favor, perdónenme.

Declare @TableA  Table
(
  aId INT,
  aName VARCHAR(50),
  bId INT
)
Declare @TableB  Table
(
  bId INT,
  bName VARCHAR(50)  
)

Declare @TableC  Table
(
  cId INT,
  cName VARCHAR(50),
  dId INT
)
Declare @TableD  Table
(
  dId INT,
  dName VARCHAR(50)  
)

DECLARE @StartTime DATETIME;
SELECT @startTime = GETDATE();

DECLARE @i INT;

SET @i = 1;

WHILE @i < 1000000
BEGIN
  INSERT INTO @TableB VALUES(@i, 'nameB:' + CONVERT(VARCHAR, @i))
  INSERT INTO @TableA VALUES(@i+5, 'nameA:' + CONVERT(VARCHAR, @i+5), @i)

  SET @i = @i + 1;
END

SELECT @startTime = GETDATE()

DELETE a
--SELECT *
FROM @TableA a
Inner Join @TableB b
ON  a.BId = b.BId
WHERE a.aName LIKE '%5'

SELECT Duration = DATEDIFF(ms,@StartTime,GETDATE())

SET @i = 1;
WHILE @i < 1000000
BEGIN
  INSERT INTO @TableD VALUES(@i, 'nameB:' + CONVERT(VARCHAR, @i))
  INSERT INTO @TableC VALUES(@i+5, 'nameA:' + CONVERT(VARCHAR, @i+5), @i)

  SET @i = @i + 1;
END

SELECT @startTime = GETDATE()

DELETE c
--SELECT *
FROM @TableC c
Inner Join @TableD d
ON  c.DId = d.DId
AND c.cName LIKE '%5'

SELECT Duration    = DATEDIFF(ms,@StartTime,GETDATE())

Si puede obtener una buena razón de este script o escribir otro útil, por favor comparta. Gracias y espero esta ayuda.

QMaster
fuente
1

Supongamos que tiene 2 tablas, una con un conjunto Maestro (por ejemplo, empleados) y otra con un conjunto secundario (por ejemplo, Dependientes) y desea deshacerse de todas las filas de datos en la tabla Dependientes que no pueden activarse. con cualquier fila en la tabla maestra.

delete from Dependents where EmpID in (
select d.EmpID from Employees e 
    right join Dependents d on e.EmpID = d.EmpID
    where e.EmpID is null)

El punto a tener en cuenta aquí es que solo está recolectando una 'matriz' de EmpIDs de la unión primero, utilizando ese conjunto de EmpIDs para realizar una operación de eliminación en la tabla Dependientes.

beauXjames
fuente
1

En SQLite, lo único que funciona es algo similar a la respuesta de beauXjames.

Parece que todo se reduce a esto DELETE FROM table1 WHERE table1.col1 IN (SOME TEMPORARY TABLE); y que una tabla temporal puede ser creada por SELECT y JOIN a sus dos tablas, que puede filtrar esta tabla temporal en función de la condición en la que desea eliminar los registros en la Tabla1.

Bhoom Suktitipat
fuente
1

puedes ejecutar esta consulta: -

Delete from TableA 
from 
TableA a, TableB b 
where a.Bid=b.Bid
AND [my filter condition]
Aditya
fuente
1

La forma más simple es:

DELETE TableA
FROM TableB
WHERE TableA.ID = TableB.ID
Carlos Barini
fuente
1
DELETE FROM table1
where id IN 
    (SELECT id FROM table2..INNER JOIN..INNER JOIN WHERE etc)

Minimice el uso de consultas DML con combinaciones. Debería poder hacer la mayoría de las consultas DML con subconsultas como las anteriores.

En general, las combinaciones solo deben usarse cuando necesita SELECCIONAR o GRUPAR por columnas en 2 o más tablas. Si eres solo toca varias tablas para definir una población, use subconsultas. Para consultas DELETE, use subconsulta correlacionada.

1c1cle
fuente