如何在Microsoft SQL Server 2008中为给定用户选择最新事件?

时间:2012-11-07 09:30:10

标签: sql sql-server sql-server-2008

我在Microsoft SQL Server 2008中有一个数据库

我有一个表[eventlog].[dbo].[USER_OPERATION],其中包含[userID], [event_description], [event_date], [event_type], [eventID]

eventID对于每一个可能发生的特定事件都是独一无二的。

给定的UserID当然不是唯一的事件(每个用户可能有很多与他相关的事件)但与单个用户相关联

我想要的是创建一个查询,该查询会为我提供一个列表,其中只包含每个用户的最新事件(也就是说,每个UserID)及其相关信息(特定事件的event_typeeventIDevent_description

举例说明:

执行时

SELECT * 
FROM [eventlog].[dbo].[USER_OPERATION] 
ORDER BY userID ASC

我得到的是

|====================================================================================|
|  eventID  |  userID  |        event_description        |  event_date  | event_type |
|           |          |                                 |              |            |
|   123     |    2     |  USER 2 broke something         |  03.11.11    |   CRASH    |
|   391     |    2     |  USER 2 filed a complaint       |  30.04.10    |  COMPLAINT |
|   392     |    2     |  USER 2 has bought beer         |  31.10.09    |  PURCHASE  |
|   32      |    3     |  USER 3 broke something         |  22.10.11    |   CRASH    |
|   568     |    4     |  USER 4 has requested support   |  05.12.11    |  SUPP_REQ  |
|   691     |    4     |  USER 4 has bought beer         |  01.12.10    |  PURCHASE  |
|   81      |    4     |  USER 4 updated personal data   |  17.07.11    |  PDAT_UPD  |
|   141     |    5     |  USER 5 has bought beer         |  16.08.11    |  PURCHASE  |
|   142     |    5     |  USER 5 broke something         |  16.08.11    |   CRASH    |
|   269     |    6     |  USER 6 updated personal data   |  27.01.12    |  PDAT_UPD  |
|   845     |    7     |  USER 7 updated personal data   |  27.01.12    |  PDAT_UPD  |
|           |          |                                 |              |            |
|====================================================================================|

如您所见,某些用户拥有多个与其关联的日期不同的事件。

我想要的是一个查询,它会显示一个用户列表以及用户有一个事件的最新日期(输出本质上是一个列出每个用户一次的表,并显示最新的与每个用户关联的事件,以及关联的event_description,event_date和event_type info)。

我们将这样的查询结果称为“最近事件表”。

请注意用户5(用户ID 5)在同一天破坏并买啤酒的“异常情况”。

在这种情况下,我不关心两个当天事件中的哪一个会进入“最近事件表”,它可以随机选择或其他任何事情(虽然我仍然需要关联的event_description和event_type信息。)

理想情况下,结果看起来像这样(对于同一组用户):

|====================================================================================|
|  eventID  |  userID  |        event_description        |  event_date  | event_type |
|           |          |                                 |              |            |
|   123     |    2     |  USER 2 broke something         |  03.11.11    |   CRASH    |
|   32      |    3     |  USER 3 broke something         |  22.10.11    |   CRASH    |
|   568     |    4     |  USER 4 has requested support   |  05.12.11    |  SUPP_REQ  |
|   141     |    5     |  USER 5 has bought beer         |  16.08.11    |  PURCHASE  |
|   269     |    6     |  USER 6 updated personal data   |  27.01.12    |  PDAT_UPD  |
|   845     |    7     |  USER 7 updated personal data   |  27.01.12    |  PDAT_UPD  |
|           |          |                                 |              |            |
|====================================================================================|

如果没有办法“随机选择两个中的任何一个或按照某些规则”为用户5选择“日期欺骗”,在“最近事件表”中有两个条目“对于这种特殊情况是可以接受的,因为它们非常罕见,我可以手动处理它们。

在这种(稍微不那么幸运)的情况下,“近期事件表”看起来像

|====================================================================================|
|  eventID  |  userID  |        event_description        |  event_date  | event_type |
|           |          |                                 |              |            |
|   123     |    2     |  USER 2 broke something         |  03.11.11    |   CRASH    |
|   32      |    3     |  USER 3 broke something         |  22.10.11    |   CRASH    |
|   568     |    4     |  USER 4 has requested support   |  05.12.11    |  SUPP_REQ  |
|   141     |    5     |  USER 5 has bought beer         |  16.08.11    |  PURCHASE  |
|   142     |    5     |  USER 5 broke something         |  16.08.11    |   CRASH    |
|   269     |    6     |  USER 6 updated personal data   |  27.01.12    |  PDAT_UPD  |
|   845     |    7     |  USER 7 updated personal data   |  27.01.12    |  PDAT_UPD  |
|           |          |                                 |              |            |
|====================================================================================|

这也是可以接受的(但稍后需要进行一些额外的修剪)。

那么,总结一下我的问题,是否有可能构建一个这样的Microsoft SQL查询,它会给我一个与上述内容一致的最近事件表?

非常感谢您的帮助

2 个答案:

答案 0 :(得分:1)

您可以将CTE(公用表表达式)与ROW_NUMBER()函数结合使用:

;WITH CTE AS 
(
    SELECT  
       *,
       RowNum = ROW_NUMBER() OVER (PARTITION BY UserID 
                                   ORDER BY event_date DESC, event_id DESC)
    FROM [eventlog].[dbo].[USER_OPERATION] 
)
SELECT *
FROM CTE
WHERE RowNum = 1

将您的数据“划分”为多个组 - 每个UserID一个 - 然后按event_date DESCevent_id DESC对该数据组内的事件进行排序并对其进行编号 - 最近的条目(对于每个用户)获得RowNum = 1 - 所以只需从CTE中选择那些就完成了!

答案 1 :(得分:0)

DECLARE @USER_OPERATION table 
(
eventID int,
userID int,
event_description nvarchar(250),
event_date date,
event_type nvarchar(250)
)
Insert into @USER_OPERATION values  (123,2,'USER 2 broke something','11/03/11','CRASH')
Insert into @USER_OPERATION values  (391,2,'USER 2 filled a complaint','04/30/10','COMPLAINT')
Insert into @USER_OPERATION values  (392,2,'USER 2 bought beer','10/31/09','PURCHASE')
Insert into @USER_OPERATION values  (32,3,'USER 3 broke something','10/22/11','CRASH')
Insert into @USER_OPERATION values  (568,4,'USER 4 has requested support','12/05/11','SUPP_REQ')
Insert into @USER_OPERATION values  (691,4,'USER 4 has bought beer','12/01/10','PURCHASE ')
Insert into @USER_OPERATION values  (81,4,'USER 4 updated personal data','07/17/11','PDAT_UPD ')
Insert into @USER_OPERATION values  (141,5,' USER 5 has bought beer','08/16/11','PURCHASE')
Insert into @USER_OPERATION values  (142,5,' USER 5 broke something','08/16/11','CRASH')
Insert into @USER_OPERATION values  (269,6,'USER 6 updated personal data','01/27/12','PDAT_UPD')
Insert into @USER_OPERATION values  (845,7,'USER 7 updated personal data ','01/27/12','PDAT_UPD')


SELECT * FROM @USER_OPERATION AS userOp INNER JOIN
(SELECT DISTINCT userID, (SELECT Top 1 eventID FROM @USER_OPERATION a WHERE a.userID  =B.userID ORDER BY event_date DESC)as eventID
from @USER_OPERATION AS B) as tbl 
ON userOp.userID =tbl.userID and userOp.eventID =tbl.eventID