2009-07-02 5 views
0

Imaginez que j'ai ces colonnes dans un tableau:Comment supprimer lorsque le paramètre varie par groupe sans boucle? (T-SQL)

id int NOT NULL IDENTITY PRIMARY KEY, 
instant datetime NOT NULL, 
foreignId bigint NOT NULL 

Pour chaque groupe (regroupés par foreignId) Je veux supprimer toutes les lignes qui sont à 1 heure de plus que le maximum (instant). Ainsi, pour chaque groupe, le paramètre est différent.

Est-il possible sans boucler?

Répondre

1
DELETE 
FROM mytable 
FROM mytable mto 
WHERE instant < 
     (
     SELECT DATEADD(hour, -1, MAX(instant)) 
     FROM mytable mti 
     WHERE mti.foreignid = mto.foreignid 
     ) 

note à double FROM clause, il est sur le but, sinon vous ne serez pas en mesure de créer un alias de la table vous supprimez de.

Les données d'échantillon pour vérifier:

DECLARE @mytable TABLE 
     (
     id INT NOT NULL PRIMARY KEY, 
     instant DATETIME NOT NULL, 
     foreignID INT NOT NULL 
     ) 

INSERT 
INTO @mytable 
SELECT 1, '2009-22-07 10:00:00', 1 
UNION ALL 
SELECT 2, '2009-22-07 09:30:00', 1 
UNION ALL 
SELECT 3, '2009-22-07 08:00:00', 1 
UNION ALL 
SELECT 4, '2009-22-07 10:00:00', 2 
UNION ALL 
SELECT 5, '2009-22-07 08:00:00', 2 
UNION ALL 
SELECT 6, '2009-22-07 07:30:00', 2 

DELETE 
FROM @mytable 
FROM @mytable mto 
WHERE instant < 
     (
     SELECT DATEADD(hour, -1, MAX(instant)) 
     FROM @mytable mti 
     WHERE mti.foreignid = mto.foreignid 
     ) 

SELECT * 
FROM @mytable 

1 2009-07-22 10:00:00.000 1 
2 2009-07-22 09:30:00.000 1 
4 2009-07-22 10:00:00.000 2 
+0

Je pensais depuis longtemps que ça fonctionnait, mais malheureusement, votre requête ne fait rien. –

+0

@Jader: voir la mise à jour de la publication avec des exemples de données. – Quassnoi

+0

Désolé. Il ne fonctionnait pas à cause de certains champs nuls, maintenant avec isnull (nullableField, -1) au bon endroit cela fonctionne –

4

Oui, c'est assez simple. Essayez ceci:

DELETE mt 
FROM MyTable AS mt 
WHERE mt.instant <= DATEADD(hh, -1, (SELECT MAX(instant) 
             FROM MyTable 
             WHERE ForeignID = mt.ForeignID)) 

Ou ceci:

;WITH MostRecentKeys 
AS 
(SELECT ForeignID, MAX(instant) AS LatestInstant 
FROM MyTable) 

DELETE mt 
FROM MyTable AS mt 
JOIN MostRecentKeys mrk ON mt.ForeignID = mrt.ForeignID 
     AND mt.Instant <= DATEADD(hh, -1, mrk.LatestInstant) 
0

Je vais supposer que quand vous dites '1 heure de plus que le maximum (instantanée) vous voulez dire « 1 heure de plus que le maximum (instantanée) pour cet ID étranger '.

Étant donné que, il y a certainement une façon plus succincte que cela, mais il fonctionnera:

DELETE 
    TableName 
WHERE 
    DATEADD(hh, 1, instant) < (SELECT MAX(instant) 
           FROM TableName T2 
           WHERE T2.foreignId = TableName.foreignId) 

La sous-requête interne est appelée une « sous-requête corrélée », si vous voulez regarder pour plus d'informations. La façon dont cela fonctionne est que pour chaque ligne considérée par la requête externe, c'est la de que la ligne est référencée par la sous-requête.

Questions connexes