附近时间戳的SQL查询组

时间:2012-11-06 22:26:58

标签: sql sql-server group-by

我有一个带有时间戳列的表。我希望能够通过标识符列(例如cusip)进行分组,对另一列进行求和(例如数量),但仅适用于彼此在30秒内的行,即在固定的行中30秒的铲斗间隔。鉴于数据:

       cusip| quantity|    timestamp
============|=========|=============
BE0000310194|      100| 16:20:49.000
BE0000314238|       50| 16:38:38.110
BE0000314238|       50| 16:46:21.323
BE0000314238|       50| 16:46:35.323

我想写一个返回的查询:

       cusip| quantity
============|=========
BE0000310194|      100
BE0000314238|       50
BE0000314238|      100

编辑: 此外,如果我还可以从查询中获取MIN(时间戳),它将大大简化事情。

3 个答案:

答案 0 :(得分:0)

以下可能对您有所帮助。

在给定时间内分组30秒的时间段。这是'2012-01-01 00:00:00'。 DATEDIFF计算时间戳值和说明时间之间的秒数。然后将其除以30得到分组列。

SELECT MIN(TimeColumn) AS TimeGroup, SUM(Quantity) AS TotalQuantity FROM YourTable
GROUP BY (DATEDIFF(ss, TimeColumn, '2012-01-01') / 30)

此处每组的最小时间戳将输出为TimeGroup。但是你可以使用最大或偶数分组列值再次转换为时间进行显示。

答案 1 :(得分:0)

根据上面的评论,我假设克里斯想要的第一种情况(即使值1和3不在彼此的30秒之内,但在值2的30秒之内,所有3个都被分组了) 。还要假设表中的每一行都有一些唯一的ID,称为“ id”。您可以执行以下操作:

  1. 创建一个新的分组,确定分区中的前一行是否比当前行晚30秒以上(例如,确定是否需要新的30秒分组,或者继续前一个分组)。我们将其称为parent_id。
  2. 在parent_id上的总数(加上任何其他聚合)

代码看起来像这样

$(hostname)

答案 2 :(得分:0)

从 Sean G 解决方案中,我删除了完整表格上的 Group By。事实上,对 Oracle SQL 的几个部分重新命名。

首先找到上次后,分配自己的父ID。如果在 Previous Time 中有一个 null,那么我们排除给它一个 ID。

现在基于通过避免空值来获取最近的自父 ID,以便所有最近的 30 秒 cusip 都属于一个组。

由于有一个 CUSIP 列,我假设数据集将是大型市场交易数据。而不是在完整的表上使用 group by,而是使用 CUSIP 分区和最终的 Group Parent ID 以获得更好的性能。

SELECT
id,
sub.parent_id,
sub.cusip,
timestamp,
quantity,
sum(sub.quantity) OVER(
    PARTITION BY cusip, parent_id
) sum_quantity,
MIN(sub.timestamp) OVER(
    PARTITION BY cusip, parent_id
) min_timestamp
FROM
(
    SELECT
        base_sub.*,
        CASE
            WHEN base_sub.self_parent_id IS NOT NULL THEN
                base_sub.self_parent_id
            ELSE
                LAG(base_sub.self_parent_id) IGNORE NULLS OVER(
                    PARTITION BY cusip
                    ORDER BY
                        timestamp, id
                )
        END parent_id
    FROM
        (
            SELECT
                c.*,
                CASE
                    WHEN nvl(abs(EXTRACT(SECOND FROM to_timestamp(previous_timestamp, 'yyyy/mm/dd hh24:mi:ss') - to_timestamp
                    (timestamp, 'yyyy/mm/dd hh24:mi:ss'))), 31) > 30 THEN
                        id
                    ELSE
                        NULL
                END self_parent_id
            FROM
                (
                    SELECT
                        my_table.id,
                        my_table.cusip,
                        my_table.timestamp,
                        my_table.quantity,
                        LAG(my_table.timestamp) OVER(
                            PARTITION BY my_table.cusip
                            ORDER BY
                                my_table.timestamp, my_table.id
                        ) previous_timestamp
                    FROM
                        my_table
                ) c
        ) base_sub
) sub

下面是表格行

输入数据:

Input Data

下面是输出

结果

RESULT