Sql 按时间间隔将结果集的子集分组
我有一个审计表,其中记录了特定的操作(如“访问”、“创建”、“更新”等)。我正在选择这些记录,以便它们可以在表中显示给管理用户 当我为一个特定的实体选择所有记录时,这种方法可以很好地工作。但是,由于我使用的是Post-Redirect-Get模式,“访问”记录记录在每个页面视图上。在一个典型的会话中,最终用户可能会在同一个5分钟窗口内点击同一页面6或7次。因此,管理用户必须滚动浏览相当多的冗余访问记录,这会分散用户体验的注意力,这是可以理解的 为了解决这个问题,我编写了两个查询。第一个将查找所有不是access记录的记录。第二个将查找访问记录,然后将它们分组为10分钟的间隔。然后我将Sql 按时间间隔将结果集的子集分组,sql,sql-server,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允许我上传的数据量有限)
我觉得有一种更好的方法可以做到这一点,它不需要我使用
UNION
。为了做到这一点,我不得不将TEXT
列转换为VARCHAR
列,我觉得可能有更好的选择。关于如何改进此查询的任何建议?使用这两个分组消除联合。第二个表达式也成为在列上创建的组合的新表达式。第一个也可用于控制排序,然后以其他方式丢弃。(不要忘记在action\u type\u id
上卸下过滤器):
当操作类型id为1,然后1其他2结束时,
操作类型id为1时的情况
然后在
else-DATEADD(分钟,日期差(分钟,0,[创建日期])/10*10,0)
结束
这将导致查询将这两种类型的操作视为不同的操作,以便进行聚合。因为您确实希望使用非1动作保持每一行,所以根本不需要将它们折叠成10分钟的块
请注意,如果有可能用相同的时间戳记录两行这样的数据,那么这种方法就不太管用了。您需要在另一个ID上分组(或仅使用行编号()
)来绕过此问题,但我怀疑这是不必要的。使用这两个分组来消除联合。第二个表达式也成为在
列上创建的组合的新表达式。第一个也可用于控制排序,然后以其他方式丢弃。(不要忘记在action\u type\u id
上卸下过滤器):
当操作类型id为1,然后1其他2结束时,
操作类型id为1时的情况
然后在
else-DATEADD(分钟,日期差(分钟,0,[创建日期])/10*10,0)
结束
这将导致查询将这两种类型的操作视为不同的操作,以便进行聚合。因为您确实希望使用非1动作保持每一行,所以根本不需要将它们折叠成10分钟的块
请注意,如果有可能用相同的时间戳记录两行这样的数据,那么这种方法就不太管用了。你需要在另一个ID上分组(或者只是行号()
)来绕过这个问题,但我怀疑这是不必要的。嗨,肖恩-我不确定我是否遵守了。操作类型Id可以是1到6之间的值。我上传到SQLFiddle的示例并不代表所有可能的值,因为它在“模式”中可以上传多少数据方面存在一些不幸的限制。我想也许我看到了你的想法,但是1和2只是一些可能的行动值type@lofacture把1和2想象成你联盟中两个部分的名字。它实际上与动作类型值无关。您可以轻松地将它们更改为任何您认为更具描述性的内容,如“Access”和“Other”或任何您喜欢的内容。SQL不是我最擅长的技能-我仍然无法理解这两个case语句的用途-它们应该替换我的union关键字?看起来您可能建议我将这两条语句添加到第二个查询的GROUPBY部分,并一起删除最上面的查询。当我这样做的时候,我确实会把我的创作分成十分钟的间隔。但是我失去了结果集中的其他动作类型。我的错误。我忘了从第二个查询WHERE子句中删除WHERE ACTION\u TYPE\u ID=1。让我再看一看,确保这是正确的。我的原始union和新查询之间的结果集非常不同。我不得不对你打算把它们放在哪里做一些假设。谢谢你的努力,但是我很难理解你的意思。嗨,肖恩,我不确定我是否明白。操作类型Id可以是1到6之间的值。我上传到SQLFiddle的示例并不代表所有可能的值,因为它在“模式”中可以上传多少数据方面存在一些不幸的限制。我想也许我看到了你的想法,但是1和2只是一些可能的行动值type@lofacture把1和2想象成你联盟中两个部分的名字。它实际上与动作类型值无关。您可以轻松地将它们更改为任何您认为更具描述性的内容,如“Access”和“Other”或任何您喜欢的内容。SQL不是我最擅长的技能-我仍然无法理解这两个case语句的用途-它们应该替换我的union关键字?看起来您可能建议我将这两条语句添加到第二个查询的GROUPBY部分,并一起删除最上面的查询。当我这样做的时候,我确实会把我的创作分成十分钟的间隔。但是我失去了结果集中的其他动作类型。我的错误。我忘了从第二个查询WHERE子句中删除WHERE ACTION\u TYPE\u ID=1。让我再看一眼,确保这是正确的
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