2012-10-05 28 views
4

我已經得到了我想要寫一個從動作表顯示最近StatusID數據的查詢。修復我的SQL查詢視圖

這裏是我的數據庫看起來像(截圖從SQL Server 2008):

screenshot

從我的樣本數據中,可以看到的是,行動表包含RequestID#26兩(2)項。我只想顯示最近StatusID值(基於DateStamp場)。

screenshot2

我已經創建了我的數據庫視圖。它看起來很討厭,並且碰到了我的SQL寫作能力。

SELECT 
    P.ID AS PacketID, R.ID AS RequestID, A.ID AS ActionID, A.EmpID, P.DateStamp, 
    RQ.Description AS RequestType, L.Description AS Line, R.PartNo, R.Workorder, 
    R.Qty, RZ.Description AS ReasonType, R.MTF, S.Description AS Status 
FROM Packet AS P 
    LEFT OUTER JOIN Request AS R ON R.PacketID = P.ID 
    INNER JOIN Action AS A ON A.RequestID = R.ID 
    INNER JOIN RequestType AS RQ ON R.RequestTypeID = RQ.ID 
    INNER JOIN Line AS L ON R.LineID = L.ID 
    INNER JOIN ReasonType AS RZ ON R.ReasonTypeID = RZ.ID 
    INNER JOIN Status AS S ON A.StatusID = S.ID 

這個觀點,但是,正顯示出值的所有,我需要以某種方式只拉最近的行對於任何給定的行動。

我將如何修改我查看做到這一點?

回答

1

您可以創建,抓住最大日期戳的請求ID分組(這會給你的每個請求ID的最新日期戳)的動作表派生表。獲得派生表之後,可以將其加回到Action表中具有與給定RequestID相匹配的最新DateStamp的行上的Action表。

SELECT 
P.ID AS PacketID, R.ID AS RequestID, A.ID AS ActionID, A.EmpID, P.DateStamp, 
RQ.Description AS RequestType, L.Description AS Line, R.PartNo, R.Workorder, 
R.Qty, RZ.Description AS ReasonType, R.MTF, S.Description AS Status 
FROM Packet AS P 
LEFT OUTER JOIN Request AS R ON R.PacketID = P.ID 

INNER JOIN 
(SELECT RequestID, MAX(DateStamp) AS MostRecentDateStamp 
FROM Action GROUP BY RequestID) AS MostRecentAction 
ON R.ID = MostRecentAction.RequestID 

INNER JOIN Action AS A 
ON 
MostRecentAction.RequestID = A.RequestID 
AND 
MostRecentAction.MostRecentDateStamp = A.DateStamp 

INNER JOIN RequestType AS RQ ON R.RequestTypeID = RQ.ID 
INNER JOIN Line AS L ON R.LineID = L.ID 
INNER JOIN ReasonType AS RZ ON R.ReasonTypeID = RZ.ID 
INNER JOIN Status AS S ON A.StatusID = S.ID 

,或者另一種選擇是採取由Karwin先生這裏顯示的方法: Join single row from a table in MySQL

SELECT 
P.ID AS PacketID, R.ID AS RequestID, A.ID AS ActionID, A.EmpID, P.DateStamp, 
RQ.Description AS RequestType, L.Description AS Line, R.PartNo, R.Workorder, 
R.Qty, RZ.Description AS ReasonType, R.MTF, S.Description AS Status 
FROM Packet AS P 
LEFT OUTER JOIN Request AS R ON R.PacketID = P.ID 

INNER JOIN Action AS A 
ON 
R.ID = A.RequestID 

LEFT JOIN Action AS A2 
ON 
A.RequestID = A2.RequestID 
AND 
A.DateStamp < A2.DateStamp 

INNER JOIN RequestType AS RQ ON R.RequestTypeID = RQ.ID 
INNER JOIN Line AS L ON R.LineID = L.ID 
INNER JOIN ReasonType AS RZ ON R.ReasonTypeID = RZ.ID 
INNER JOIN Status AS S ON A.StatusID = S.ID 

WHERE A2.RequestID IS NULL 

我喜歡Karwin先生使用方法,尤其是與結構的關係問題時像你這樣:

SELECT 
P.ID AS PacketID, R.ID AS RequestID, A.ID AS ActionID, A.EmpID, P.DateStamp, 
RQ.Description AS RequestType, L.Description AS Line, R.PartNo, R.Workorder, 
R.Qty, RZ.Description AS ReasonType, R.MTF, S.Description AS Status 
FROM Packet AS P 
LEFT OUTER JOIN Request AS R ON R.PacketID = P.ID 

INNER JOIN Action AS A 
ON 
R.ID = A.RequestID 

LEFT JOIN Action AS A2 
ON 
A.RequestID = A2.RequestID 
AND 
(A.DateStamp < A2.DateStamp OR (A.DateStamp = A2.DateStamp AND A1.RequestID < A2.RequestID)) 

INNER JOIN RequestType AS RQ ON R.RequestTypeID = RQ.ID 
INNER JOIN Line AS L ON R.LineID = L.ID 
INNER JOIN ReasonType AS RZ ON R.ReasonTypeID = RZ.ID 
INNER JOIN Status AS S ON A.StatusID = S.ID 

WHERE A2.RequestID IS NULL 
+0

這似乎是我的情況的最佳解決方案。我唯一使用它的方法就是我對'INNER','LEFT'和'OUTER' ** JOIN **的理解程度不滿意。如果我不得不編輯這個* View *,我不會理解發生了什麼!但是,我真的很喜歡它! – jp2code

+1

@ jp2code - 在第一個解決方案中,使用了INNER JOIN,因爲它確保在GROUP BY與它所派生的表連接時會有匹配的行。在第二種解決方案中,使用了LEFT JOIN,因爲當表與自身連接時,連接條件的狀態如下:連接有比此行更大的時間戳的行 - 並且無法滿足該條件時在具有最大DateStamp的行上),那麼你已經找到了你正在尋找的東西(A2.RequestID將是空的),並且你用WHERE子句選擇了這個。 – dugas

+0

許多偉大的答案,併爲所有人+1。最後,我選擇了這個版本,因爲我最喜歡它的風格。是否更好,更差或等同於其他嵌套查詢版本?我真的不知道。 – jp2code

1
SELECT 
    P.ID AS PacketID, R.ID AS RequestID, A.ID AS ActionID, A.EmpID, P.DateStamp, 
    RQ.Description AS RequestType, L.Description AS Line, R.PartNo, R.Workorder, 
    R.Qty, RZ.Description AS ReasonType, R.MTF, S.Description AS Status 
FROM Packet AS P 
    LEFT OUTER JOIN Request AS R ON R.PacketID = P.ID 
    INNER JOIN Action AS A ON A.RequestID = R.ID 
    INNER JOIN RequestType AS RQ ON R.RequestTypeID = RQ.ID 
    INNER JOIN Line AS L ON R.LineID = L.ID 
    INNER JOIN ReasonType AS RZ ON R.ReasonTypeID = RZ.ID 
    INNER JOIN Status AS S ON A.StatusID = S.ID 
where A.StatusID = (
    select top 1 StatusID 
    from Action 
    where RequestID = R.ID 
    order by DateStamp desc 
    ) 
+0

我不認爲A. StatusID是唯一的,你不應該使用時間戳嗎? – Hogan

+0

+1。這確實拉我之後的結果。 SELECT TOP 1子查詢處理的速度是否比包含額外的'INNER JOIN'作爲dugas'答案更快? – jp2code

+1

@ jp2code它會更快,但它在某些(邊緣?)情況下也是錯誤的。 – Hogan

1

爲了更好地實現你想要什麼,你可以加入到一個子查詢分組由封包ID的結果和EA選擇MAX(ID) ch packetID。這是有效的,因爲ID字段是一個標識列,所以最高的數字總是最近的。這比在時間戳上進行比較更可取,因爲整數(特別是索引整數)比時間戳要快得多。

SELECT 
    P.ID AS PacketID, R.ID AS RequestID, A.ID AS ActionID, A.EmpID, P.DateStamp, 
    RQ.Description AS RequestType, L.Description AS Line, R.PartNo, R.Workorder, 
    R.Qty, RZ.Description AS ReasonType, R.MTF, S.Description AS Status 
FROM Packet AS P 
    LEFT OUTER JOIN (SELECT MAX(ID) as ID FROM Request GROUP BY PacketID) as UR ON P.ID = UR.ID 
    INNER JOIN Request AS R ON R.PacketID = UR.ID 
    INNER JOIN Action AS A ON A.RequestID = R.ID 
    INNER JOIN RequestType AS RQ ON R.RequestTypeID = RQ.ID 
    INNER JOIN Line AS L ON R.LineID = L.ID 
    INNER JOIN ReasonType AS RZ ON R.ReasonTypeID = RZ.ID 
    INNER JOIN Status AS S ON A.StatusID = S.ID 
+0

最大(ID)不起作用查看示例數據。 (27> 26但有較早的時間戳) – Hogan

+0

+1。感謝您的工作,但是這返回了0行。供參考:它也出現在網站** spencerdrager **下降。 – jp2code

1

這會奏效。

WITH MaxDate AS 
(
    SELECT RequestID, Max(DateStamp) AS MaxDate 
    FROM Action 
    GROUP BY RequestID 
), ActionFiltered AS 
(
    SELECT Action.* 
    FROM Action 
    JOIN MaxDate ON Action.RequestID=MaxDate.RequestID AND Action.DateStamp = MaxDate.MaxDate 
) 
SELECT 
    P.ID AS PacketID, R.ID AS RequestID, A.ID AS ActionID, A.EmpID, P.DateStamp, 
    RQ.Description AS RequestType, L.Description AS Line, R.PartNo, R.Workorder, 
    R.Qty, RZ.Description AS ReasonType, R.MTF, S.Description AS Status 
FROM ActionFiltered A 
JOIN Request AS R ON A.RequestID = R.ID 
JOIN Packet AS P ON P.ID = R.PacketID 
JOIN RequestType AS RQ ON R.RequestTypeID = RQ.ID 
JOIN Line AS L ON R.LineID = L.ID 
JOIN ReasonType AS RZ ON R.ReasonTypeID = RZ.ID 
JOIN Status AS S ON A.StatusID = S.ID 

下面是我在做什麼:首先,對於每個請求ID我找到最當前日期(MAXDATE),然後我得到的所有的動作表對這些行中的數據(ActionFiltered),最後我同回到你的表與內部連接。

可能存在的問題:如果在Action表中有兩個具有相同requestID和timestamp的記錄,則會在最終表中獲得兩行。

注:我沒有測試,所以可能會有錯別字。

+0

這很有趣。我目前不使用任何'WITH'語句,因爲我最近正在從SQL 2000遷移到SQL Server 2008.但是,當我嘗試運行查詢時,我收到*「Msg 8156,Level 16,State 1,Line 7:「RequestID」列被多次指定爲「ActionFiltered」。「*我沒有聲明SQL 2008,所以這可能是一個更新版本的功能。 – jp2code

+0

@ jp2code:在我的部分,不要輸入錯字,將其改爲「SELECT Action。*'。我改變了答案,謝謝你的追趕 – Hogan

1

我通常使用rank()來獲取基於時間的最新版本的記錄。它會根據您提供的密鑰(分區:在本例中是請求ID)爲每個記錄版本分配一個等級。如果按desc排序,排名爲1的行是最新的。如果按順序排序,排名爲1的行最早。

編輯:更改了子查詢中返回的RequestId列的名稱,以消除您所看到的錯誤。

SELECT 
    P.ID AS PacketID, R.ID AS RequestID, A.ID AS ActionID, A.EmpID, P.DateStamp, 
    RQ.Description AS RequestType, L.Description AS Line, R.PartNo, R.Workorder, 
    R.Qty, RZ.Description AS ReasonType, R.MTF, S.Description AS Status 
FROM Packet AS P 
    LEFT OUTER JOIN Request AS R ON R.PacketID = P.ID 
    INNER JOIN (
     select 
       req.ID as RequestIdForJoin 
       , act.* 
       , rank() over (partition by req.ID order by act.DateStamp desc) as [Rank] 
      from Request as req 
       inner join Action as act on req.ID = act.RequestID 
    ) as A 
     on R.ID = A.RequestIdForJoin 
    INNER JOIN RequestType AS RQ ON R.RequestTypeID = RQ.ID 
    INNER JOIN Line AS L ON R.LineID = L.ID 
    INNER JOIN ReasonType AS RZ ON R.ReasonTypeID = RZ.ID 
    INNER JOIN Status AS S ON A.StatusID = S.ID   
    where A.[Rank] = 1 

重複動作:如果@霍根的相同的時間戳多個動作的情況是可能的,你可以在臺上,然後刪除重複這樣的:

declare @View table (
PacketID int, RequestID int, ActionID int, EmpID int, DateStamp datetime, 
RequestType int, Line int, PartNo varchar(50), Workorder int, Qty int, 
ReasonType int, MTF varchar(50), Status int 
) 

insert into @View  
SELECT 
    P.ID AS PacketID, R.ID AS RequestID, A.ID AS ActionID, A.EmpID, P.DateStamp, 
    RQ.Description AS RequestType, L.Description AS Line, R.PartNo, R.Workorder, 
    R.Qty, RZ.Description AS ReasonType, R.MTF, S.Description AS Status 
FROM Packet AS P 
    LEFT OUTER JOIN Request AS R ON R.PacketID = P.ID 
    INNER JOIN (
     select 
       req.ID as RequestIdForJoin 
       , act.* 
       , rank() over (partition by req.ID order by act.DateStamp desc) as [Rank] 
      from Request as req 
       inner join Action as act on req.ID = act.RequestID 
    ) as A 
     on R.ID = A.RequestIdForJoin 
    INNER JOIN RequestType AS RQ ON R.RequestTypeID = RQ.ID 
    INNER JOIN Line AS L ON R.LineID = L.ID 
    INNER JOIN ReasonType AS RZ ON R.ReasonTypeID = RZ.ID 
    INNER JOIN Status AS S ON A.StatusID = S.ID   
    where A.[Rank] = 1 

-- Removing all but one duplicate 
;with dups as (
    select 
     RequestID 
     ,row_number() over (partition by RequestID order by DateStamp) as [RowNumber] 
    from @View 
) 
delete dups where [RowNumber] > 1 

select * from @View 
+0

+1。像Hogan的回答一樣,我也遇到了'A'多次指定'RequestID'的錯誤。這是用於SQL Server 2008之後的嗎? – jp2code

+1

這隻意味着名爲'RequestId'的列正在爲子查詢'A'返回兩次。我重命名了'RequestId',因此它是唯一的 - 現在應該可以工作。 – andes

+0

謝謝!我不經常使用SQL來善於調試錯誤,就像使用Windows窗體一樣。 – jp2code