SQL Server: alternativa al uso de un predicado en una cláusula WHERE

SQL Server: alternativa al uso de un predicado en una cláusula WHERE

Me gustaría eliminar todos los eventos en mi DemoTable donde la diferencia entre el primer evento y el último evento para esa interacción es mayor a 30 minutos. Escribí una declaración de selección para ver todos estos eventos y usé la palabra clave HAVING para obtener los eventos que tienen un DATEDIFF de más de 30 minutos.

Dado que no puedo usar HAVING en una eliminación o usar un predicado en una cláusula WHERE, ¿cuál es la mejor alternativa/forma correcta de hacer lo que quiero hacer en el código incorrecto a continuación...

DELETE
FROM dbo.DemoTable dt
WHERE DATEDIFF(MINUTE, MIN(dt.utc), MAX(dt.utc)) > 30
GROUP BY dt.interactionId;
GO

EDITAR: ¡Gracias a todos por sus sugerencias!

Mostrar la mejor respuesta

¿Funciona la consulta que escribiste en la pregunta?

@ErayBalkanli No, la consulta en mi pregunta devuelve un error que indica que no se permite usar un predicado en una cláusula WHERE.

Avatar Dai
Respuesta aceptada

Una forma rápida y sucia es así:

DELETE FROM
    dbo.DemoTable
WHERE
    dto.DemoTable.YourPrimaryKey IN
    (
        SELECT
            YourPrimaryKey
        FROM
            -- your query here
    )

Esto solo funciona para claves primarias no compuestas.

Esto funciona bien para mí, gracias! Parece una buena manera de lograr lo que estoy tratando de hacer, entonces, ¿por qué te refieres a ella como una forma rápida y sucia?

Avatar Dai

@David Bueno, porque no puedes usarlo con claves primarias compuestas.

Ah, está bien, normalmente no uso claves primarias compuestas, así que esto es bueno para mí :).

Creo que una de las alternativas es usar una tabla tentativa que contenga los datos válidos y usar esos datos para eliminar los no válidos como a continuación:

SELECT dt.interactionid
INTO #temp
FROM DemoTable dt
WHERE DATEDIFF(MINUTE, MIN(dt.utc), MAX(dt.utc)) <= 30

DELETE dt
FROM DemoTable dt
WHERE NOT EXISTS (select * from #temp t where t.interactionid = dt.interactionid)

¿Una consulta secundaria?

delete from dbo.demotable
where interactionid in 
    (select dt.interactionid
    from dbo.demotable dt
    WHERE DATEDIFF(MINUTE, MIN(dt.utc), MAX(dt.utc)) > 30
    GROUP BY dt.interactionId)

dependiendo de la versión de sql, puede eliminarlo así:

delete from dt
from dbo.demotable dt
WHERE DATEDIFF(MINUTE, MIN(dt.utc), MAX(dt.utc)) > 30

Si desea eliminar todas estas interacciones, puede usar una combinación o un CTE actualizable. Yo optaría por lo último:

with todelete as (
      select dt.*, 
             min(dt.utc) over (partition by dt.interactionId) as min_utc,
             max(dt.utc) over (partition by dt.interactionId) as max_utc
      from dbo.DemoTable dt
     )
delete from todelete
    where datediff(day, min_utc, max_utc) > 30;

Puedes usar subconsultas

DELETE FROM dbo.DemoTable dt
WHERE id IN (
    SELECT id FROM dbo.DemoTable
    -- The rest of your query
)
GO