4

我有一个正在尝试编写的查询,它显示 Action 表中的最新状态 ID数据。

这是我的数据库的样子(来自 SQL Server 2008 的屏幕截图):

截屏

从我的示例数据中,您可以看到 Action 表包含RequestID#26 的两 (2) 个条目。我只想显示最新的StatusID值(基于DateStamp字段)。

截图2

我为我的数据库创建了一个视图。它看起来很讨厌,并且影响了我的 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

但是,此视图显示了所有值,我需要它以某种方式仅拉取任何给定操作的最新行。

我将如何修改我的视图来做到这一点?

4

5 回答 5

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
    )
于 2012-10-05T22:20:17.337 回答
1

您可以从 Action 表中创建一个派生表,该表获取按 RequestID 分组的最大 DateStamp(这将为您提供每个 RequestID 的最新 DateStamp)。获得派生表后,您可以将其连接回 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
于 2012-10-05T22:27:37.397 回答
1

要实现您想要的,您可以加入一个子查询,按 packetID 对结果进行分组,并为每个 packetID 选择 MAX(ID)。这是有效的,因为 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
于 2012-10-06T00:50:43.360 回答
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

这是我正在做的事情:首先,对于每个 requestID,我找到最新的日期(MaxDate),然后我从操作表中获取这些行的所有数据(ActionFiltered),最后我将所有这些数据加入到您的表中内连接。

潜在问题:如果 Action 表中有两条记录具有相同的 requestID 和时间戳,您将在最终表中获得两行。

注意:我没有测试,所以可能有错别字。

于 2012-10-06T03:27:17.490 回答
1

我通常使用 rank() 根据时间获取最新版本的记录。它将根据您提供的键(分区:在本例中为请求 ID)为记录的每个版本分配一个等级。如果按 desc 排序,排名为 1 的行是最新的。如果按 asc 排序,排名为 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 

对于重复的操作:如果@Hogan 的具有相同时间戳的多个操作的场景是可能的,您可以像这样暂存然后删除重复项:

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
于 2012-10-06T05:14:08.610 回答