修复我的SQL查询视图

时间:2012-10-05 22:06:41

标签: sql tsql

我有一个我想写的查询,它显示了Action表中最近的 StatusID 数据。

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

screenshot

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

screenshot2

我为我的数据库创建了一个View。这看起来很讨厌,并且突破了我的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

然而,这个视图显示了所有值,并且我需要它以某种方式仅拉出任何给定Action的最新行。

我如何修改我的视图来执行此操作?

5 个答案:

答案 0 :(得分: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
    )

答案 1 :(得分:1)

您可以从Action表创建派生表,该表抓取按RequestID分组的最大DateStamp(这将为每个RequestID提供最新的DateStamp)。获得派生表后,可以将其连接回Action表中行的Action表,该表具有与给定RequestID匹配的最新DateStamp。

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

我喜欢卡尔温先生使用的方法,特别是在处理与你所拥有的结构的关系时:

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

答案 2 :(得分:1)

要获得所需内容,您可以加入子查询,通过packetID对结果进行分组,并为每个packetID选择MAX(ID)。这是有效的,因为ID字段是一个标识列,因此最高的数字将始终是最新的。这比在时间戳上进行比较更可取,因为int(特别是索引的int)比时间戳要快得多。

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

答案 3 :(得分: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和时间戳的记录,那么最终表中会有两行。

注意:我没有测试,所以可能存在拼写错误。

答案 4 :(得分: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