【问题标题】:Query Records and Group by a block of time按时间段查询记录和分组
【发布时间】:2011-05-17 19:18:54
【问题描述】:

我有一个应用程序,它可能一天运行多次。每次运行都会将数据写入表中以报告发生的事件。主报告表如下所示:

Id    SourceId    SourceType    DateCreated
5048  433         FILE          5/17/2011 9:14:12 AM
5049  346         FILE          5/17/2011 9:14:22 AM
5050  444         FILE          5/17/2011 9:14:51 AM
5051  279         FILE          5/17/2011 9:15:02 AM
5052  433         FILE          5/17/2011 12:34:12 AM
5053  346         FILE          5/17/2011 12:34:22 AM
5054  444         FILE          5/17/2011 12:34:51 AM
5055  279         FILE          5/17/2011 12:35:02 AM

我知道有两次运行,但我想要一种能够查询日期范围、进程运行次数的方法。我想要一个查询,结果是进程开始的时间和组中的文件数。这个查询让我得到了我想要的东西,我可以看到运行的日期和时间以及运行了多少文件,但不完全是我想要的。例如,它不适合从 8:58 到 9:04 的跑步。例如,它还会对在 9:02 和 9:15 开始的跑步进行分组。

Select dateadd(day,0,datediff(day,0,DateCreated)) as [Date], datepart(hour, DateCreated) as [Hour], Count(*) [File Count]
From   MyReportTable
Where DateCreated between '5/4/2011' and '5/18/2011'
    and SourceType = 'File'
Group By dateadd(day,0,datediff(day,0,DateCreated)), datepart(hour, DateCreated)
Order By dateadd(day,0,datediff(day,0,DateCreated)), datepart(hour, DateCreated)

我知道任何靠近的跑步都可能会被组合在一起,我对此很好。我只希望得到一个粗略的分组。

谢谢!

【问题讨论】:

    标签: sql sql-server gaps-and-islands


    【解决方案1】:

    如果您确定这些运行是连续的并且不重叠,您应该能够使用 Id 字段来分解您的组。查找仅相隔 1 的 Id 字段和大于某个阈值的 datecreated 字段。从您的数据来看,一次运行中的记录似乎最多在一分钟内输入,因此安全阈值可能是一分钟或更长时间。

    这将为您提供开始时间

    SELECT mrtB.Id, mrtB.DateCreated
    FROM MyReportTable AS mrtA
    INNER JOIN MyReportTable AS mrtB
        ON (mrtA.Id + 1) = mrtB.Id
    WHERE DateDiff(mi, mrtA.DateCreated, mrtB.DateCreated) >= 1
    

    我称之为 DataRunStarts

    现在您可以使用它来获取有关小组开始和结束位置的信息

    SELECT drsA.Id AS StartID, drsA.DateCreated, Min(drsB.Id) AS ExcludedEndId
    FROM DataRunStarts AS drsA, DataRunStarts AS drsB
    WHERE (((drsB.Id)>[drsA].[id]))
    GROUP BY drsA.Id, drsA.DateCreated
    

    我将其称为 DataRunGroups。我将最后一个字段称为“已排除”,因为它保存的 id 将用于定义将被拉出的 id 集的结束边界。

    现在我们可以使用 DataRunGroups 和 MyReportTable 来获取计数

    SELECT DataRunGroups.StartID, Count(MyReportTable.Id) AS CountOfRecords
    FROM DataRunGroups, MyReportTable
    WHERE (((MyReportTable.Id)>=[StartId] And (MyReportTable.Id)<[ExcludedEndId]))
    GROUP BY DataRunGroups.StartID;
    

    我将其称为 DataRunCounts

    现在我们可以将 DataRunGroups 和 DataRunCounts 放在一起来获取开始时间和计数。

    SELECT DataRunGroups.DateCreated, DataRunCounts.CountOfRecords
    FROM DataRunGroups
    INNER JOIN DataRunCounts
        ON DataRunGroups.StartID = DataRunCounts.StartID;
    

    根据您的设置,您可能需要在一个查询中完成所有这些操作,但您明白了。此外,第一次和最后一次运行不会包含在其中,因为第一次运行没有开始 id,最后一次运行也没有结束 id。要包括这些,您将只查询这两个范围,并将它们与旧的 DataRunGroups 查询结合在一起以创建一个新的 DataRunGroups。使用 DataRunGroups 的其他查询将按上述方式工作。

    【讨论】:

    • 添加 Sql 否则不可能 ;) 我明白你在说什么,但我不知道如何用 SQL 编写它。我当然可以将逻辑放在消费代码中,而不是期望 sql 提供它。
    • 在您发布 sql 之前,我开始尝试弄乱它。我得到的基本上和你得到的一样,但是发现通过加入 id-1 而不是 +1 我得到了起始范围,只有第一组退出了。哪个老了,我不在乎。感谢您的帮助。
    • 很高兴我能帮上忙。这个当然很有趣 :) 对 id-1 的调用很好。
    【解决方案2】:

    再往前走几步:

    SELECT
        Count(Id), 
        DATEPART(year, DateCreated) As yr, 
        DATEPART(month, DateCreated) As mth, 
        DATEPART(day, DateCreated) As day, 
        DATEPART(Hour, DateCreated) as hr, 
        DATEPART(minute, DateCreated) as mnt
    FROM 
        MyReportTable
    WHERE DateCreated between '5/4/2011' and '5/18/2011'
        and SourceType = 'File'
    GROUP BY 
        DATEPART(year, DateCreated), 
        DATEPART(month, DateCreated), 
        DATEPART(day, DateCreated), 
        DATEPART(Hour, DateCreated),
        DATEPART(minute, DateCreated)
    ORDER BY 
        DATEPART(year, DateCreated),
        DATEPART(month, DateCreated), 
        DATEPART(day, DateCreated), 
        DATEPART(Hour, DateCreated),
        DATEPART(minute, DateCreated)
    

    编辑

    要达到 15 分钟的分辨率,请将最后一列更改为

    (DATEPART(minute, DateCreated)/15)
    

    (在选择中添加 +1 以获得 1,2,3,4)。

    【讨论】:

    • 除了更多的列之外,这并没有真正增加我所拥有的任何东西。如果可能的话,我希望得到比每小时更好的分辨率。
    • @NerdFury 编辑了我的答案。添加了分钟列以提高分辨率。您有具体的解决方案吗?
    • 我知道你在那里做了什么。现在跑步大约需要 6 分钟,所以 10 到 15 分钟就足够了。这里的问题是它仍然基于绝对时间范围(即 9:00 - 9:15、9:15 - 9:30),因此在一个时间范围内开始并在另一个时间范围内结束的任何运行都将显示为两次运行。我最初的问题可能不够清楚。如果 pheedbaq 可以为他的解决方案提供 sql(或者如果可以,我会接受你的回答),我认为这更符合我正在寻找的内容。不过,我赞成你坚持我。不过,我可能会更好地在代码中分组。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-16
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    相关资源
    最近更新 更多