5

我有一个带有时间戳列的表。我希望能够按标识符列(例如 cusip)进行分组,对另一列(例如数量)求和,但仅适用于彼此之间 30 秒内的行,即不是固定的 30 秒桶间隔。给定数据:

       尖头| 数量| 时间戳
============|=========|=============
BE0000310194| 100| 16:20:49.000
BE0000314238| 50| 16:38:38.110
BE0000314238| 50| 16:46:21.323
BE0000314238| 50| 16:46:35.323

我想写一个返回的查询:

       尖头| 数量
============|=========
BE0000310194| 100
BE0000314238| 50
BE0000314238| 100

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

4

3 回答 3

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 输出。但是您可以使用最大值甚至分组列值,可以再次转换为时间进行显示。

于 2012-11-07T05:43:24.543 回答
0

看看上面的评论,我假设 Chris 的第一个场景是你想要的(所有 3 个都被分组,即使值 1 和 3 不在彼此的 30 秒内,而是在值 2 的 30 秒内)。还要假设表中的每一行都有一些唯一的 ID,称为“id”。您可以执行以下操作:

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

代码可能看起来像这样

select
    sub.parent_id,
    sub.cusip,
    min(sub.timestamp) min_timestamp,
    sum(sub.quantity) quantity
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
                        my_table.cusip
                    order by
                        my_table.timestamp,
                        my_table.id
                    ) 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,
                    case
                        when datediff(
                            second, 
                            nvl(previous_timestamp, to_date('1900/01/01', 'yyyy/mm/dd')),
                            my_table.timestamp) > 30
                        then my_table.id
                        else null
                    end self_parent_id
                from
                    my_table
            ) base_sub
    ) sub
group by
    sub.time_group_parent_id,
    sub.cusip
于 2019-07-17T19:49:30.840 回答
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

下面是表格行

输入数据:

输入数据

下面是输出

结果

结果

于 2021-03-06T20:00:15.277 回答