按邻近时间戳划分的SQL查询组
我有一个带有时间戳列的表。我希望能够按标识符列(如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 |数量|时间戳 ============|=========|============= 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 cusip |数量 ============|========= BE0000310194 | 100 BE0000314238 | 50 BE0000314238 | 100 编辑:按邻近时间戳划分的SQL查询组,sql,sql-server,group-by,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:4
此外,如果我还可以从查询中获取MIN(时间戳),这将大大简化工作。以下内容可能会对您有所帮助 一组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)
在这里,每个组的最小时间戳将作为时间组输出。但您可以使用最大值或甚至分组列值可以再次转换为时间来显示。查看上述注释,我假设Chris的第一个场景就是您想要的场景(尽管值1和值3彼此之间的间隔不在30秒内,但每个值都在值2的间隔30秒内,但所有3个都会被分组)。还要假设表中的每一行都有一个称为“ID”的唯一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
从Sean G解决方案中,我删除了完整表上的Group By。事实上,为Oracle SQL重新调整了几个部分 在找到上一次之后,首先分配自父id。如果在上一次中有空值,那么我们排除给它一个id 现在基于通过避免空值获取最近的自父id,以便所有最近的30秒cusip都属于一个组 由于有一个CUSIP列,我假设数据集将是大型市场交易数据。在完整的表上使用GROUPBY,而使用CUSIP分区和最终的组父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
下面是表中的行
输入数据:
下面是输出
结果
考虑值1:01、1:22、1:45。第一个值和最后一个值都在中间值的30秒内,但彼此之间的距离不在30秒内。这是多少组?一个-它们都被分组在一起(但是外部值之间的间隔不是30秒)?两个-中间值组和两个外部值在30秒内相同(因此计数两次)?在实践中,变量一总是正确的。找出第一个时间戳组的逻辑是什么?这些语句中哪一个是正确的?(a) 当时间戳不晚于组中的最小时间戳30秒(即,组最多可跨越30秒)时,对行进行分组;或者(b)当时间戳不超过组中前一个时间戳的30秒时,对行进行分组(也就是说,组中包含的行数与快速连续出现的行数相同,即使可能跨越30秒)。Chris,在我看来,这就像是对第一个问题的重新表述,答案仍然是一样的,实际上,一个小组从开始到结束的时间最多为30秒。在绝大多数情况下,这实际上只需要几秒钟。但老实说,我想我可以让任何一种变体都起作用。您有针对这两个方面的纯SQL解决方案吗?现在我不得不求助于获取所有条目,并在perl中进行操作以按程序进行分组。由于我在原始帖子中提到的“非30秒桶间隔”,这将不起作用。