2010-09-21 5 views
2

J'ai une table (AU_EMPLOYEE) avec deux colonnes nommées EmployeeID (int) et LastModifiedDate (DateTime). Avec ces colonnes sont d'autres contenant des données supplémentaires sur les employés. Ceci est une table d'audit et chaque fois que les données d'un employé changent d'une manière ou d'une autre, une nouvelle ligne est ajoutée.Approche SQL Server appropriée pour récupérer ces données groupées?

Il est donc probable qu'un employé donné aura plusieurs lignes dans cette table. Je souhaite récupérer l'enregistrement le plus récent pour chaque employé, tel que déterminé par LastModifiedDate. Quelle est une bonne approche pour faire cela? Requête imbriquée ou quelque chose du genre?

Merci pour les suggestions.

Répondre

6

Vous pourriez utiliser quelque chose comme ceci pour montrer la rangée la plus récente pour chaque employé. C'est un bon usage pour la fonction ROW_NUMBER.

with ranking as 
    (
     select *, ROW_NUMBER() over(partition by EmployeeID order by LastModifiedDate desc) as rn 
     from AU_EMPLOYEE 
    ) 
    select * from ranking where rn = 1 
+1

+1, comment je le ferais –

+0

Merci pour toutes vos réponses-- appréciez-le grandement. – larryq

3

En supposant au moins SQL 2005, vous pouvez utiliser un CTE:

EDIT: Comme je l'ai signalé here et here dans le passé, assurez-vous de tester les performances. La version CTE avec MAX surpasse souvent une solution basée sur ROW_NUMBER.

;with cteMaxDate as (
    select EmployeeID, max(LastModifiedDate) as MaxDate 
     from AU_EMPLOYEE 
     group by EmployeeID 
) 
select e.EmployeeID, e.Column1, e.Column2, ... 
    from cteMaxDate md 
     inner join AU_EMPLOYEE e 
      on md.EmployeeID= e.EmployeeID 
       and md.MaxDate = e.LastModifiedDate 
+0

pour les modifications fréquentes, vous pouvez obtenir plus d'une ligne par employé –

+1

Fréquent étant à moins d'une seconde d'intervalle? Je suppose que vous faites référence à l'arrondi de la précision [DateTime] (http://msdn.microsoft.com/en-us/library/ms187819.aspx) à .000, .003, .007? Si non, veuillez expliquer plus en détail. –

+0

Oui, les mises à jour peuvent se produire "à moins d'une seconde d'intervalle". Nous avons même eu des collisions sur DB2, où la précision est en microsecondes, et non en 3 millisecondes. –

3
SELECT <your columns> 
FROM (
SELECT <your columns>, 
ROW_NUMBER() OVER(PARTITION BY EmployeeID ORDER BY LastModifiedDate DESC) AS rn 
) AS t 
WHERE rn=1 
2

La réponse de Chris Pebble est correct cependant une solution plus générale est

 
SELECT * FROM 
(SELECT EmployeeID, LastModifiedDate 
FROM AU_EMPLOYEE 
WHERE LastModifiedDate<='X' ORDER BY LastModifiedDate Desc) A 
GROUP BY A.EmployeeID 

où X est la date que vous voulez revenir dans le temps pour.

+0

Je pense que cela entraînera une erreur car 'LastModifiedDate' ne fait pas partie du' group by' ou n'est pas utilisé dans une fonction aggergate. Sans oublier que la table dérivée ne possède pas d'alias. –

+0

Ajout d'alias merci. Cela fonctionne puisque vous voulez le grouper par l'ID employé et élaguer les dates qui sont inférieures à «X». L'ordre décroissant permet de conserver la date LastModified après le regroupement. Cela fonctionne, je l'utilise. – mna

+0

Je ne crains pas. 'Msg 1033, niveau 15, état 1, ligne 4 La clause ORDER BY n'est pas valide dans les vues, fonctions inline, tables dérivées, sous-requêtes et expressions de table communes, sauf si TOP ou FOR XML est également spécifié. Msg 8120, niveau 16, état 1, ligne 1 La colonne 'A.LastModifiedDate' n'est pas valide dans la liste de sélection car elle n'est pas contenue dans une fonction d'agrégat ou la clause GROUP BY.S dans SQL Server lorsqu 'utiliser un GROUP BY, vous ne peut avoir un élément dans la liste de sélection sauf s'il se trouve dans GROUP BY ou dans une fonction aggergate comme MAX(), MIN(), SUM(), etc. –

Questions connexes