2016-09-19 48 views
2

我正在嘗試查詢文檔的最新狀態,但沒有取得任何成功。我用於查詢的表格是docs,docStatsstatusList如何查詢SQL Server 2012中的最新記錄?

docs表:

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

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 | 
+-------------+---------+-------------------------+---------+ 

statusList表:

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

使用下面的我能得到的文檔最近的文檔的狀態表:

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

的結果是正確的:

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

但我需要附加列添加到查詢,而這正是它打破。它爲docId 1添加所有記錄,因爲'stat'包含在SELECT中,並且docId 1有多個狀態。我該如何編寫此查詢以便它只返回docId 1的最新狀態?

下面是該查詢,因爲我有現在:

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 

下面是結果:

| 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 | 
+-------+------------+---------+--------+---------+--------------+-------------------------+ 

回答

3
;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 

這將是更好地使用分區ROW_NUMBER()。 MAX()使用它的方式可能會以多於1個結果結束。如果超過1,如果它們相等,則只需使用DENSE_RANK()來代替ROW_NUMBER()所在的位置。

您要前往的路線也是一個有效的方法,但您的加入條件沒有ON ds.docStatDt = mdt.MaxDate,這意味着您實際上並未將結果限制爲最後一條記錄。添加該條件可能會給你你想要的。

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 
+0

好的答案,但檢查您的文檔表別名與您選擇的列 – scsimon

+1

@scsimon謝謝我糾正了我得到的複製粘貼:) – Matt

1

一種方法,其可非常有效的使用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; 

你可以,當然,參加在狀態字符串爲好,但似乎並沒有被要點你的問題。