按时间间隔对结果集的子集进行分组

时间:2019-07-06 22:10:48

标签: sql sql-server

我有一个审核表,其中记录了特定的操作(例如“访问”,“创建”,“更新”等)。我选择这些记录是为了使它们可以在表中显示给管理用户。

当我选择特定实体的所有记录时,此方法工作正常。但是,由于我使用的是Post-Redirect-Get模式,因此“访问”记录被记录在每个页面视图上。在典型的会话中,最终用户可能会在相同的5分钟窗口中点击相同的页面6或7次。结果,管理用户不得不滚动浏览相当多的冗余访问记录,这可以理解地分散了用户体验。

为解决此问题,我编写了两个查询。第一个将查找不是访问记录的所有记录。第二个将查找访问记录,然后将它们分为十分钟的间隔。然后,我UNION这两个查询并按日期时间排序。

-- Select non 'access' records
SELECT 
     [ORIGIN_ID]
    ,[ORIGIN_ID_TYPE]
    ,[REFERENCE_ID]
    ,[REFERENCE_ID_TYPE]
    ,[ACTION_TYPE_ID]
    ,CAST([ORIGINAL_VALUE] AS VARCHAR(8000)) AS ORIGINAL_VALUE
    ,CAST([CHANGED_VALUE] AS VARCHAR(8000)) AS CHANGED_VALUE
    ,[CREATED_BY]
    ,[CREATED_ON]
FROM [HISTORY] 
WHERE [ORIGIN_ID] = 500 AND [ORIGIN_ID_TYPE] = 4 AND [ACTION_TYPE_ID] != 1

UNION

-- Select 'access' records and group them into 10 minute intervals by ts
SELECT 
     [ORIGIN_ID]
    ,[ORIGIN_ID_TYPE]
    ,[REFERENCE_ID]
    ,[REFERENCE_ID_TYPE]
    ,[ACTION_TYPE_ID]
    ,CAST([ORIGINAL_VALUE] AS VARCHAR(255)) AS ORIGINAL_VALUE
    ,CAST([CHANGED_VALUE] AS VARCHAR(255)) AS CHANGED_VALUE
    ,[CREATED_BY]
    ,DATEADD(MINUTE, DATEDIFF(MINUTE, 0, [CREATED_ON]) / 10 * 10, 0) AS CREATED_ON
FROM [HISTORY]
WHERE [ACTION_TYPE_ID] = 1 AND [ORIGIN_ID] = 500 AND [ORIGIN_ID_TYPE] = 4
GROUP BY 
     [ORIGIN_ID]
    ,[ORIGIN_ID_TYPE]
    ,[REFERENCE_ID]
    ,[REFERENCE_ID_TYPE]
    ,[ACTION_TYPE_ID]
    ,CAST([ORIGINAL_VALUE] AS VARCHAR(255))
    ,CAST([CHANGED_VALUE] AS VARCHAR(255))
    ,[CREATED_BY]
    ,DATEADD(MINUTE, DATEDIFF(MINUTE, 0, [CREATED_ON]) / 10 * 10, 0)

ORDER BY [CREATED_ON] DESC

SQLFiddle(SQLFiddle允许我上传的数据量有限)

我觉得可能有一种更好的方法可以不需要我使用UNION。为了做到这一点,我不得不将TEXT列转换为VARCHAR列,我觉得可能会有更好的选择。关于如何改进此查询的任何建议?

1 个答案:

答案 0 :(得分:0)

使用这两个分组消除联合。第二个也成为合并的{model: 'Village', id: '64'}列的新表达式。第一个也可以用于控制排序,然后以其他方式丢弃。 (也不要忘记删除created_on上的过滤器。):

action_type_id

这将导致查询出于聚合目的将两种类型的操作视为不同。由于您确实希望每一行都采用非1的动作,因此您根本不会将这些行折叠成10分钟的方块。

请注意,如果可以用相同的时间戳记录两个这样的行,这将无法正常工作。您需要对另一个ID(或仅case when action_type_id <> 1 then 1 else 2 end, case when action_type_id <> 1 then created_on else DATEADD(MINUTE, DATEDIFF(MINUTE, 0, [CREATED_ON]) / 10 * 10, 0) end )进行分组以解决该问题,但我怀疑这是不必要的。