2009-07-27 5 views
3

Imaginez les données de schéma et des exemples suivants (SQL Server 2008):utilisation de la variante de la clause GROUP BY dans TSQL

OriginatingObject 
---------------------------------------------- 
ID 
1 
2 
3 

ValueSet 
---------------------------------------------- 
ID OriginatingObjectID DateStamp 
1 1      2009-05-21 10:41:43 
2 1      2009-05-22 12:11:51 
3 1      2009-05-22 12:13:25 
4 2      2009-05-21 10:42:40 
5 2      2009-05-20 02:21:34 
6 1      2009-05-21 23:41:43 
7 3      2009-05-26 14:56:01 

Value 
---------------------------------------------- 
ID ValueSetID Value 
1 1   28 
etc (a set of rows for each related ValueSet) 

J'ai besoin pour obtenir l'ID du dernier enregistrement ValueSet pour chaque OriginatingObject. Ne supposez pas que plus l'identifiant d'un enregistrement est élevé, plus il est récent. Je ne sais pas comment utiliser correctement GROUP BY afin de s'assurer que l'ensemble des résultats regroupés pour former chaque ligne d'agrégat inclut l'ID de la ligne avec la valeur DateStamp la plus élevée pour ce regroupement. Ai-je besoin d'utiliser une sous-requête ou existe-t-il un meilleur moyen?

+0

Pour plus de clarté: vous voulez le plus récent ValueSet.ID pour chaque OriginatingObjectID? – Benjol

+0

Benjol: correct. –

Répondre

4

Vous pouvez le faire avec une sous-requête corrélée ou en utilisant IN avec plusieurs colonnes et un GROUP-BY.

Veuillez noter, GROUP-BY simple peut seulement vous amener à la liste des OriginatingIDs et des Timestamps. Pour extraire les ID ValueSet pertinents, la solution la plus propre consiste à utiliser une sous-requête.

sur plusieurs colonnes GROUP-BY (probablement plus rapide):

SELECT O.ID, V.ID 
FROM Originating AS O, ValueSet AS V 
WHERE O.ID = V.OriginatingID 
AND 
(V.OriginatingID, V.DateStamp) IN 
(
    SELECT OriginatingID, Max(DateStamp) 
    FROM ValueSet 
    GROUP BY OriginatingID 
) 

Corrélées sous-requête:

SELECT O.ID, V.ID 
FROM Originating AS O, ValueSet AS V 
WHERE O.ID = V.OriginatingID 
AND 
V.DateStamp = 
(
    SELECT Max(DateStamp) 
    FROM ValueSet V2 
    WHERE V2.OriginatingID = O.ID 
) 
+0

Notez que cela peut renvoyer des ViewSets en double au cas où vous auriez deux ValueSets les plus récents avec exactement le même horodatage (mais cela peut être le comportement requis). –

+1

... et sinon, un Max (V.ID) et un groupe supplémentaire suffiront. – Benjol

+0

Merci, même si je sais comment le faire en utilisant une sous-requête, je me demandais s'il y avait une meilleure façon de le faire en utilisant une clause group by. Des idées? –

1
SELECT OriginatingObjectID, id 
FROM (
    SELECT id, OriginatingObjectID, RANK() OVER(PARTITION BY OriginatingObjectID 
            ORDER BY DateStamp DESC) as ranking 
    FROM ValueSet) 
WHERE ranking = 1; 
+0

+1 Celui-là aussi. –

0

Cela peut être fait avec une sous-requête corrélée. Aucun GROUP-BY nécessaire.

SELECT 
    vs.ID, 
    vs.OriginatingObjectID, 
    vs.DateStamp, 
    v.Value 
FROM 
    ValueSet vs 
    INNER JOIN Value v ON v.ValueSetID = vs.ID 
WHERE 
    NOT EXISTS (
    SELECT 1 
    FROM ValueSet 
    WHERE OriginatingObjectID = vs.OriginatingObjectID 
      AND DateStamp > vs.DateStamp 
) 

Cela ne fonctionne que s'il ne peut y avoir deux égaux pour une timbres à date OriginatingObjectID dans le tableau ValueSet.

+0

Malheureusement, il peut y avoir deux valeurs de date égales –

+0

Dommage. Ensuite, un GROUP BY externe supplémentaire est requis. J'ai déjà donné +1 à Rax Olgud, sa réponse couvre assez bien les deux approches. – Tomalak

Questions connexes