Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/77.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 按时间间隔将结果集的子集分组_Sql_Sql Server - Fatal编程技术网

Sql 按时间间隔将结果集的子集分组

Sql 按时间间隔将结果集的子集分组,sql,sql-server,Sql,Sql Server,我有一个审计表,其中记录了特定的操作(如“访问”、“创建”、“更新”等)。我正在选择这些记录,以便它们可以在表中显示给管理用户 当我为一个特定的实体选择所有记录时,这种方法可以很好地工作。但是,由于我使用的是Post-Redirect-Get模式,“访问”记录记录在每个页面视图上。在一个典型的会话中,最终用户可能会在同一个5分钟窗口内点击同一页面6或7次。因此,管理用户必须滚动浏览相当多的冗余访问记录,这会分散用户体验的注意力,这是可以理解的 为了解决这个问题,我编写了两个查询。第一个将查找所有

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

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

为了解决这个问题,我编写了两个查询。第一个将查找所有不是access记录的记录。第二个将查找访问记录,然后将它们分组为10分钟的间隔。然后我将
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