从一对多关系中选择一个

时间:2011-01-28 04:58:54

标签: sql sql-server tsql greatest-n-per-group

我有一张充满活动的桌子。我被要求创建一个聚合会话表;一个会话可能有几个事件。通过具有相同的到达时间来识别会话。例如(这是一种简化,我没有输入实际的时间戳):

EventID  ArrivalTime  StartTime EndTime StaffID
1        0945         0950      0955    John
2        0945         0955      1000    Barb

可能变成类似的东西:

ArrivalTime StartTime EndTime StaffID
0945        0950      1000    ???

使用MIN(StartTime)MAX(EndTime)将其保留为一行。

正如上面的问题所示,我遇到的问题是获得一个工作人员身份证 - 这个工作人员并不重要,但我需要一个人。如果它只是一个字符串,正如我上面所示,它可以用MIN(StaffID)来完成,但我正在做的事情就是我需要在Staff表中查找StaffID并拔出与我表中的短代码相关联的GUID。并且GUID不喜欢像MIN()这样的函数。另外,更糟糕的是,事件表中的StaffID列是NULL是可行的,所以我必须坚持左连接或类似。

有人提出了一个子查询,但显然我的大脑在星期五拒绝接受这个,并且看不到如何让它工作。

作为基线,这是我当前查询的内容:

SELECT NEWID() AS SessionID,
e.ArrivalTime,
MIN(e.StartTime),
MAX(e.EndTime),
s.StaffGUID
FROM Events e LEFT JOIN Staff s ON e.StaffID = s.StaffID
GROUP BY e.ArrivalTime, s.StaffGUID

问题是如果列表中有两个不同的工作人员,会话将显示两次。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

有相关的subselect选项(使用TOP的2000+):

  SELECT NEWID() AS SessionID,
         e.ArrivalTime,
         MIN(e.StartTime),
         MAX(e.EndTime),
         (SELECT TOP 1 s.StaffGUID
            FROM STAFF s
           WHERE s.staffid = e.staffid) AS staffguid
    FROM EVENTS e
GROUP BY e.arrivaltime, e.staffguid, staffguid

...或派生表/内联视图(使用ROW_NUMBER的2005+):

  SELECT NEWID() AS SessionID,
         e.ArrivalTime,
         MIN(e.StartTime),
         MAX(e.EndTime),
         s.staffguid
     FROM EVENTS e
LEFT JOIN (SELECT t.staffid,
                  t.staffguid,
                  ROW_NUMBER() OVER (PARTITION BY t.staffid) AS rank
             FROM STAFF t) s ON s.staffid = e.staffid
                            AND s.rank = 1
 GROUP BY e.arrivaltime, s.staffguid

我的偏好是派生表 - 相关的子查询往往不能正常运行。