You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Hive SQL中统计单日各时间点前的累计交易数

问题:统计各时间点前的累计交易数(支持多日+性能优化)

示例表结构与数据

CREATE TABLE table1 (ID INT, time TIME);

INSERT INTO table1 
VALUES
(1, '11:30:00'),
(1, '14:30:00'),
(1, '18:00:00')
;

CREATE TABLE table2 (ID INT, txn_time TIME, txn_val INT);

INSERT INTO table2
VALUES
(1, '10:45:13', 1),
(1, '10:50:52', 2),
(1, '11:01:20', 4),
(1, '14:32:12', 2),
(1, '16:43:20', 5),
(1, '19:22:02', 3)
;

期望结果

┌─────────────┬──────────────┬──────────────┐
│ ID          │        time  │    txn count │
├─────────────┼──────────────┼──────────────┤
│ 1           │     11:30:00 │            3 │
│ 1           │     14:30:00 │            3 │
│ 1           │     18:00:00 │            5 │
└─────────────┴──────────────┴──────────────┘

错误的SQL代码

SELECT t1.ID,
t1.time,
sum(CASE WHEN t2.txn_time < t1.time THEN 1 END) over(PARTITION BY t1.time)
FROM table1 AS t1
LEFT JOIN table2 AS t2 on t1.ID = t2.ID
GROUP BY t1.ID, t1.time
ORDER BY t1.time

解决方案

1. 用PARTITION BY实现正确累计计数

原SQL的问题在于多对多关联后产生笛卡尔积,窗口函数的PARTITION BY t1.time无法正确计算累计数。正确做法是先对table2的交易按ID分组,用窗口函数计算累计计数,再关联table1匹配对应时间点的最大值:

WITH txn_cumulative AS (
    SELECT 
        ID,
        txn_time,
        -- 按ID分组,按交易时间排序,计算累计交易数
        COUNT(*) OVER (PARTITION BY ID ORDER BY txn_time) AS cum_count
    FROM table2
)
SELECT 
    t1.ID,
    t1.time,
    -- 取所有早于当前时间点的累计数最大值,即为该时间点的累计交易数
    COALESCE(MAX(tc.cum_count), 0) AS txn_count
FROM table1 t1
LEFT JOIN txn_cumulative tc 
    ON t1.ID = tc.ID 
    AND tc.txn_time < t1.time
GROUP BY t1.ID, t1.time
ORDER BY t1.time;

2. 支持多日场景,每日计数重置

首先需给两张表添加日期字段(如record_date和txn_date),然后在窗口函数的PARTITION BY中加入日期,确保每日计数独立重置:

-- 先更新表结构支持多日
CREATE TABLE table1 (ID INT, record_date DATE, record_time TIME);
CREATE TABLE table2 (ID INT, txn_date DATE, txn_time TIME, txn_val INT);

-- 多日版统计SQL
WITH txn_cumulative AS (
    SELECT 
        ID,
        txn_date,
        txn_time,
        -- 按ID+日期分组,每日累计计数从0开始
        COUNT(*) OVER (PARTITION BY ID, txn_date ORDER BY txn_time) AS cum_count
    FROM table2
)
SELECT 
    t1.ID,
    t1.record_date,
    t1.record_time,
    COALESCE(MAX(tc.cum_count), 0) AS txn_count
FROM table1 t1
LEFT JOIN txn_cumulative tc 
    ON t1.ID = tc.ID 
    AND t1.record_date = tc.txn_date
    AND tc.txn_time < t1.record_time
GROUP BY t1.ID, t1.record_date, t1.record_time
ORDER BY t1.record_date, t1.record_time;

3. 优化多对多关联性能

原SQL的多对多关联会产生大量中间数据,可通过以下方式优化:

  • 添加复合索引:给table2创建(ID, txn_date, txn_time)复合索引,给table1创建(ID, record_date, record_time)复合索引,加速过滤、排序和关联
  • 避免笛卡尔积:使用LATERAL JOIN(PostgreSQL)或OUTER APPLY(SQL Server)替代预计算+GROUP BY,直接针对每个时间点计算符合条件的交易数,减少中间结果集:

以PostgreSQL为例:

SELECT 
    t1.ID,
    t1.record_date,
    t1.record_time,
    COALESCE(tc.cum_count, 0) AS txn_count
FROM table1 t1
LEFT JOIN LATERAL (
    -- 直接统计当前ID、日期下,早于当前时间点的交易数
    SELECT COUNT(*) AS cum_count
    FROM table2 t2
    WHERE t2.ID = t1.ID
      AND t2.txn_date = t1.record_date
      AND t2.txn_time < t1.record_time
) tc ON true
ORDER BY t1.record_date, t1.record_time;

内容的提问来源于stack exchange,提问作者Pete

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 22:55:17