web-dev-qa-db-fra.com

Récupération du dernier enregistrement de chaque groupe de la base de données - SQL Server 2005/2008

J'ai fait quelques recherches en ne parvenant pas à obtenir les résultats que je recherche. Fondamentalement, nous avons quatre systèmes de gestion différents en place dans notre entreprise et je suis en train de combiner régulièrement toutes les données de chaque système. Mon objectif est de mettre à jour les données toutes les heures dans une base de données centrale. Voici un exemple de jeu de données avec lequel je travaille:

COMPUTERNAME | SERIALNUMBER | USERNAME | LASTIP | LASTUPDATE | SOURCE
TEST1 | 1111 | BOB | 1.1.1.1 | 1/17/2011 01:00:00 | MGMT_SYSTEM_1
TEST1 | 1111 | BOB | 1.1.1.1 | 1/18/2011 01:00:00 | MGMT_SYSTEM_2
TEST1 | 1111 | PETER | 1.1.1.11 | 1/19/2011 01:00:00 | MGMT_SYSTEM_3
TEST2 | 2222 | GEORGE | 1.1.1.2 | 1/17/2011 01:00:00 | MGMT_SYSTEM_1
TEST3 | 3333 | TOM | 1.1.1.3 | 1/19/2011 01:00:00 | MGMT_SYSTEM_2
TEST4 | 4444 | MIKE   | 1.1.1.4 | 1/17/2011 01:00:00 | MGMT_SYSTEM_1
TEST4 | 4444 | MIKE   | 1.1.1.41 | 1/19/2011 01:00:00 | MGMT_SYSTEM_3
TEST5 | 5555 | SUSIE  | 1.1.1.5 | 1/19/2011 01:00:00 | MGMT_SYSTEM_1

Je souhaite donc interroger cette table principale et récupérer uniquement le dernier enregistrement (basé sur LASTUPDATE) de cette façon, je peux obtenir les dernières informations sur ce système. Le problème est qu'un système peut être dans chaque base de données, mais bien sûr, ils n'auront jamais le même temps de mise à jour exact.

Je m'attendrais à obtenir quelque chose comme ça:

TEST1 | 1111 | PETER | 1.1.1.11 | 1/19/2011 01:00:00 | MGMT_SYSTEM_3
TEST2 | 2222 | GEORGE | 1.1.1.2 | 1/17/2011 01:00:00 | MGMT_SYSTEM_1
TEST3 | 3333 | TOM | 1.1.1.3 | 1/19/2011 01:00:00 | MGMT_SYSTEM_2
TEST4 | 4444 | MIKE   | 1.1.1.41 | 1/19/2011 01:00:00 | MGMT_SYSTEM_3
TEST5 | 5555 | SUSIE  | 1.1.1.5 | 1/19/2011 01:00:00 | MGMT_SYSTEM_1

J'ai essayé d'utiliser la fonction MAX, mais avec cela je ne peux récupérer qu'une seule colonne. Et je ne peux pas l'utiliser dans une sous-requête car je n'ai pas de champ d'identification unique qui me donnerait le dernier enregistrement mis à jour. L'un des systèmes est une base de données MySQL et la fonction MAX de MySQL fonctionnera en fait comme j'en ai besoin pour ne renvoyer qu'un seul enregistrement par GROUP BY, mais elle ne fonctionne pas dans SQL Server.

Je pense que je dois utiliser MAX et LEFT JOIN, mais mes tentatives ont échoué jusqu'à présent.

Votre aide serait grandement appréciée. Cela fait 3 ou 4 heures que j'essaye de me creuser la tête en essayant d'obtenir une requête qui fonctionne. Cette table principale se trouve sur un serveur SQL Server 2005.

Merci!

27
RyanF
;with cteRowNumber as (
    select COMPUTERNAME, SERIALNUMBER, USERNAME, LASTIP, LASTUPDATE, SOURCE,
           row_number() over(partition by COMPUTERNAME order by LASTUPDATE desc) as RowNum
        from YourTable
)
select COMPUTERNAME, SERIALNUMBER, USERNAME, LASTIP, LASTUPDATE, SOURCE
    from cteRowNumber
    where RowNum = 1
57
Joe Stefanelli

Dans SQL Server, la solution la plus performante est souvent une sous-requête corrélée:

select t.*
from t
where t.lastupdate = (select max(t2.lastupdate)
                      from t t2
                      where t2.computername = t.computername
                     );

En particulier, cela peut bénéficier d'un index sur (computername, lastupdate). Conceptuellement, la raison pour laquelle cela est plus rapide que row_number() est que cette requête filtre simplement les lignes qui ne correspondent pas. La version row_number() doit attacher le numéro de ligne à toutes les lignes, avant de filtrer - c'est plus de traitement de données.

11
Gordon Linoff