web-dev-qa-db-fra.com

Sélection de l'enregistrement max pour chaque utilisateur

Cela semble si cela devrait être assez simple, mais je bute en essayant de trouver une solution qui fonctionne pour moi.

J'ai une table member_contracts qui a la structure (simplifiée) suivante.

MemberID | ContractID   | StartDate | End Date |
------------------------------------------------
1          1              2/1/2002    2/1/2003
2          2              3/1/2002    3/1/2003
3          3              4/1/2002    4/1/2003
1          4              2/1/2002    2/1/2004
2          5              3/1/2003    2/1/2004
3          6              4/1/2003    2/1/2004

J'essaie de créer une requête qui sélectionnera les contrats les plus récents de ce tableau. Cela étant la sortie suivante pour ce petit exemple:

MemberID | ContractID   | StartDate | End Date |
------------------------------------------------
1          4              2/1/2002    2/1/2004
2          5              3/1/2003    2/1/2004
3          6              4/1/2003    2/1/2004

Faire cela sur une base par utilisateur est extrêmement simple car je peux simplement utiliser une sous-requête pour sélectionner le max contractID pour l'utilisateur spécifié. J'utilise SQL Server, donc s'il y a une façon spéciale de le faire avec cette saveur, je suis prêt à l'utiliser. Personnellement, j'aimerais quelque chose qui soit agnostique au moteur.

Mais comment pourrais-je écrire une requête qui atteindrait l'objectif pour tous les utilisateurs?

EDIT: Je dois également ajouter que je recherche la valeur max contractID pour chaque utilisateur, pas les dates les plus récentes.

31
Scott

Cette solution utilise l'unicité du champ ContractId:

SELECT MemberID, ContractID, StartDate, EndDate
FROM member_contracts 
WHERE ContractId IN (
    SELECT MAX(ContractId)
    FROM member_contracts 
    GROUP BY MemberId
)

Voir le fonctionnement en ligne: sqlfiddle

37
Mark Byers

La façon la plus sûre de le faire est avec row_number

select MemberId, ContractId, StartDate, EndDate
from (select mc.*,
             row_number() over (partition by MemberId order by contractId desc) seqnum
      from Member_Contracts mc
     ) mc
where seqnum = 1

Cela gère le cas de plusieurs contrats pour le même membre. . . ce qui peut ne pas vraiment être un problème dans ces données.

15
Gordon Linoff