Comment interroger l'logging le plus récent dans SQL Server 2012?

J'essaye d'interroger le statut le plus récent d'un document, mais n'ayant aucun succès. Les tables que j'utilise pour ma requête sont docs , docStats et statusList .

table de docs :

 | docId | docTitle | venIdFk | +-------+------------+---------+ | 1 | Contract 1 | 81 | | 2 | Contract 2 | 37 | +-------+------------+---------+ 

Table docStats :

 | docStatIdPk | docStat | docStatDt | docIdFk | +-------------+---------+-------------------------+---------+ | 7 | 1 | 2016-09-16 09:00:00.000 | 1 | | 10 | 2 | 2016-09-16 09:30:00.000 | 1 | | 11 | 4 | 2016-09-17 08:30:00.000 | 1 | | 12 | 1 | 2016-09-17 10:00:00.000 | 2 | +-------------+---------+-------------------------+---------+ 

table statusList :

 | statId | stat | +--------+--------------+ | 1 | Needs Review | | 2 | In Review | | 3 | Denied | | 4 | Accepted | +--------+--------------+ 

En utilisant ce qui suit, je peux get le statut le plus récent des documents dans la table docs:

 SELECT d2.docId, MAX(ds2.docStatDt) AS maxStatDt FROM docs d2 INNER JOIN docStats ds2 ON d2.docId = ds2.docIdFk GROUP BY d2.docId 

Le résultat est correct:

 | docId | maxStatDt | +-------+-------------------------+ | 1 | 2016-09-17 08:30:00.000 | | 2 | 2016-09-17 10:00:00.000 | +-------+-------------------------+ 

Mais j'ai besoin d'append des colonnes supplémentaires à la requête, et c'est là que ça casse. Il ajoute tous les loggings pour docId 1 car 'stat' est inclus dans SELECT, et il y a plusieurs statuts pour docId 1. Comment puis-je écrire cette requête pour qu'elle ne renvoie que l'état le plus récent de docId 1?

Voici la requête telle que je l'ai maintenant:

 SELECT d.docid, d.doctitle, d.doctype, d.docorg, d.docdept, s.stat, mdt.maxdate AS crntDocStatDtSet FROM docs d INNER JOIN docstats ds ON d.docid = ds.docidfk INNER JOIN statuslist s ON ds.docstat = s.statid INNER JOIN (SELECT d2.docid, Max(ds2.docstatdt) AS MaxDate FROM docs d2 INNER JOIN docstats ds2 ON d2.docid = ds2.docidfk GROUP BY d2.docid) mdt ON d.docid = mdt.docid WHERE d.docid = '1' GROUP BY d.docid, d.doctitle, d.doctype, d.docorg, d.docdept, s.stat, mdt.maxdate 

Voici les résultats:

 | docId | docTitle | docType | docOrg | docDept | stat | crntDocStatDtSet | +-------+------------+---------+--------+---------+--------------+-------------------------+ | 1 | Contract 1 | 3 | 3 | 2 | Accepted | 2016-09-17 08:30:00.000 | | 1 | Contract 1 | 3 | 3 | 2 | In Review | 2016-09-17 08:30:00.000 | | 1 | Contract 1 | 3 | 3 | 2 | Needs Review | 2016-09-17 08:30:00.000 | +-------+------------+---------+--------+---------+--------------+-------------------------+ 

 ;WITH cte AS ( SELECT d.docId, d.docTitle, d.doctype, d.docOrg, d.docDept, s.stat, ROW_NUMBER() OVER (PARTITION BY d.docId ORDER BY ds.docStatDt DESC) as RowNumber FROM docs d INNER JOIN docStats ds ON d.docId = ds.docIdFk INNER JOIN statusList s ON ds.docStat = s.statId ) SELECT * FROM cte WHERE RowNumber = 1 

Il vaudrait mieux utiliser un ROW_NUMBER partitionné (). MAX () la façon dont vous l'utilisez pourrait aboutir à plus d'un résultat. Si plus de 1 serait désiré s'ils sont égaux alors utilisez simplement DENSE_RANK () à la place de ROW_NUMBER ().

L'itinéraire que vous suivez est également une méthode valide, mais votre condition ON pour votre jointure ne comportait pas ON ds.docStatDt = mdt.MaxDate, ce qui signifiait que vous ne limitiez pas réellement vos résultats au dernier logging. L'ajout de cette condition vous donnerait probablement ce que vous voulez aussi.

  SELECT d.docId, d.docTitle, d.doctype, d.docOrg, d.docDept, s.stat, mdt.MaxDate AS crntDocStatDtSet FROM docs d INNER JOIN docStats ds on d.docId = ds.docIdFk INNER JOIN statusList s ON ds.docStat = s.statId INNER JOIN ( SELECT d2.docId, MAX(ds2.docStatDt) as MaxDate FROM docs d2 INNER JOIN docStats ds2 ON d2.docId = ds2.docIdFk GROUP BY d2.docId ) mdt ON d.docId = mdt.docId AND ds.docStatDt = mdt.MaxDate WHERE d.docId = '1' GROUP BY d.docId, d.docTitle, d.doctype, d.docOrg, d.docDept, s.stat, mdt.MaxDate 

Une méthode qui peut être très efficace consiste à utiliser outer apply :

 select d.*, ds.* from docs d outer apply (select top 1 ds.* from docstats ds where ds.docIdFk = d.docId order by docStatDt desc ) ds; 

Bien sûr, vous pouvez également vous joindre à la string de statut, mais cela ne semble pas être le sens de votre question.