2012-10-05 31 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