0

给定约 50,000 条记录,其中有两个datetime字段表示每行的开始时间和结束时间,我如何编写 SQL Server 查询来构建一个直方图,其中包含开始日期和结束日期之间任意时间跨度的桶,例如30 分钟、0-1 小时, 1-2 小时、2-4 小时、4-8 小时、8-24 小时、24-48 小时、48-72 小时、3-5 天、7 天以上

我希望有一种聪明的方法可以避免对每个存储桶(在本例中为 10 个)执行查询。我使用 LINQ-to-SQL 作为轻量级 ORM,但原始 SQL 也可以。

我天真的方法是先将所有内容存储 60 分钟,然后执行子查询以提取每个不规则存储桶。

编辑: LINQ 版本的奖励积分,因为我刚刚了解到可以CASE在 LINQ 中生成语句。持续时间表和CASE语句之间的任何性能注意事项?

4

3 回答 3

0

一种 linq 方法(只需几个时间间隔即可理解)

var i30m = TimeSpan.FromMinutes(30).TotalMinutes;
var i60m = TimeSpan.FromMinutes(60).TotalMinutes;
var i2h = TimeSpan.FromHours(2).TotalMinutes;

context.Records.Select(t => SqlMethods.DateDiffMinute(t.StartTime, t.EndTime))
      .GroupBy(i => i < i30m
                      ? "0-30 m"
                      : i < i60m
                          ? "30-60 m"
                          : i < i2h
                              ? "1-2 h"
                              : "Long")
      .Select(i => new {i.Key, Count = i.Count()})

SqlMethods为 linq to sql 提供 SQL Server 函数。

于 2013-02-08T14:35:11.443 回答
0

尝试这个:

SELECT Periods.Period, SUM(Price)
FROM
(
    SELECT '2013-01-01 10:00:00' AS StartDate, '2013-01-01 10:30:00' AS EndDate, 10 AS Price
    UNION ALL
    SELECT '2013-01-01 09:00:00' AS StartDate, '2013-01-01 10:00:00' AS EndDate, 20 AS Price
    UNION ALL
    SELECT '2013-01-01 11:00:00' AS StartDate, '2013-01-01 13:00:00' AS EndDate, 30 AS Price
    UNION ALL
    SELECT '2013-01-01 13:00:00' AS StartDate, '2013-01-01 15:00:00' AS EndDate, 40 AS Price
    UNION ALL
    SELECT '2013-01-01 10:00:00' AS StartDate, '2013-01-01 13:00:00' AS EndDate, 50 AS Price
) AS Prices
INNER JOIN 
(
    SELECT 1 AS Period
    UNION ALL
    SELECT 2 AS Period
    UNION ALL 
    SELECT 3 AS Period
) AS Periods
ON DATEDIFF(HOUR, Prices.StartDate, Prices.EndDate) < Periods.Period
GROUP BY Periods.Period

在您的表格中,您可以计算开始日期和结束日期之间的持续时间,然后将其与您的时期(据我所知 - x 轴值)加入表格并按这些时期分组。

于 2013-02-08T13:14:45.170 回答
0

说你有

SomeTable(Key,StartDate,EndDate)

Select Key,DateDiff(minute,StartDate,EndDate) From SomeTable as RawValue

会给你每把钥匙和分钟差

所以

Select Key,
Case When RawValue < 30 Then "Less than 30 minutes"
Case When RawValue between 30 and 60 then "Less than an hour"
...
else 'Over 7 days' as HistValue
From
(
Select Key,DateDiff(minute,StartDate,EndDate) From SomeTable as RawValue
) RawValues

会给你每个键和差异的范围

所以

Select HistValue,Count(*) From
(
Select Key,
Case When RawValue < 30 Then "Less than 30 minutes"
Case When RawValue between 30 and 60 then "Less than an hour"
...
else 'Over 7 days' as HistValue
From
(
Select Key,DateDiff(minute,StartDate,EndDate) From SomeTable as RawValue
) RawValues
) UncountedValues

你能一口气给你很多吗,反正我的头上。

如果您想要一个更通用的解决方案,那么一种方法是定义一个持续时间表

例如

Category        MinMinutes MaxMinutes
"Less than 30"  0         30

取出硬编码并加入

例如

Inner join Duration On BucketMinutes between MinMinutes and MaxMinutes
于 2013-02-08T13:16:05.797 回答