时间段合并算法

该代码示例展示了如何使用Python的pandas和SQLAlchemy库与MySQL数据库交互,分批查询数据,进行数据合并操作。程序首先连接数据库,然后从原始表ori_event分批读取数据,同时获取最新结果表target_event的数据。通过比较两表数据,进行合并处理,更新或插入到目标表中,实现数据的实时同步和合并。
摘要由CSDN通过智能技术生成

from urllib.parse import quote_plus

import pandas as pd
from sqlalchemy import create_engine

"""
原始表:

create table ori_event
(
    id         int auto_increment
        primary key,
    begin_date datetime null,
    end_date   datetime null,
    cnt        int      null
);

结果表:
create table target_event
(
    id         int auto_increment
        primary key,
    begin_date datetime null,
    end_date   datetime null,
    cnt        int      null
);

"""

db_username = "user1"
db_pwd = ""
db_host = ""
db_port = "3306"
db_name = "tmp_data"


def get_mysql_conn():
    mysql_conn = "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8mb4"
    mysql_conn_pro = mysql_conn.format(db_username, quote_plus(db_pwd), db_host, db_port, db_name)
    return create_engine(mysql_conn_pro, pool_pre_ping=True)


def ori_batch_query(batch_size=10) -> pd.DataFrame:
    """
     分批查询需要时间合并的源数据
    :param batch_size: 每批大小
    :return:
    """
    conn = get_mysql_conn()
    sql = "select * from ori_event  where begin_date is not null and end_date is not null and  id > (select max(id) from target_event) order by 1"

    # 读表头
    columns = conn.execute("show columns from ori_event")
    pd_column = pd.DataFrame(columns)
    column_name = pd_column.iloc[:, 0].array

    # 读取数据

    limit = " limit 0," + str(batch_size)
    data = conn.execute(sql + limit)
    result = pd.DataFrame(data, columns=column_name)

    # 改成日期类型
    result["begin_date"] = pd.to_datetime(result["begin_date"])
    result["end_date"] = pd.to_datetime(result["end_date"])
    return result


def load_latest_target() -> pd.DataFrame:
    """
    加载最新的、已完成合并的结果表
    :return:
    """

    # todo 将条件中的1=1改成真实条件!目标:只读取需要参与合并的结果集,避免内存占用过大,如,只取当天的数据
    sql = "select * from target_event  where 1 = 1 and begin_date is not null and end_date is not null order by 1"

    conn = get_mysql_conn()
    # 读表头
    columns = conn.execute("show columns from target_event")
    pd_column = pd.DataFrame(columns)
    column_name = pd_column.iloc[:, 0].array

    data = conn.execute(sql)
    result = pd.DataFrame(data, columns=column_name)

    result["begin_date"] = pd.to_datetime(result["begin_date"])
    result["end_date"] = pd.to_datetime(result["end_date"])
    return result


def del_target_by_ids(del_ids):
    if del_ids is not None and len(del_ids) > 0:
        conn = get_mysql_conn()
        sql = "delete from target_event where id in ({})".format(",".join([str(i) for i in del_ids]))
        conn.execute(sql)


def save_target(result):
    if result is None or len(result) == 0:
        return

    conn = get_mysql_conn()
    for i, row in result.iterrows():
        sql = "insert into target_event (id,begin_date,end_date,cnt) values ({},'{}','{}',{})".format(row["id"],
                                                                                                      row["begin_date"],
                                                                                                      row["end_date"],
                                                                                                      row["cnt"])
        conn.execute(sql)


def merge(event: pd.DataFrame, latest: pd.DataFrame):
    if event is None or len(event) == 0:
        return

    del_ids = list()

    for i, row in event.iterrows():
        print("开始处理以下数据:")
        print("----------------------------")
        print(row.to_frame().T)
        print("----------------------------")

        less_than_min = row["end_date"] < latest["begin_date"]
        more_than_max = row["begin_date"] > latest["end_date"]

        match_data = latest[~(less_than_min | more_than_max)]
        if len(match_data) > 0:
            #  将匹配到的结果以及需要处理的这条记录,合并成新的结果
            print("处理方式:需要合并,rows = ", len(match_data))
            tmp = pd.concat([match_data, row.to_frame().T], ignore_index=True)
            new_min = tmp["begin_date"].min()
            new_max = tmp["end_date"].max()

            # todo 修改这里,合并的逻辑
            new_cnt = tmp["cnt"].sum()
            tmp_data = [
                [row["id"], new_min, new_max, new_cnt]
            ]

            tmp_df = pd.DataFrame(data=tmp_data, columns=latest.columns)

            # 从原结果中删除匹配到的数据,用合并后的结果替代
            del_ids.extend(match_data["id"].values)
            latest = latest.drop(labels=match_data.index)
            latest = pd.concat([latest, tmp_df], ignore_index=True)
        else:
            latest = pd.concat([latest, row.to_frame().T])
            print("处理方式:无交集,直接加入结果集")

        print("本行数据处理完成,最新结果数据: \n", latest)

    # 删除被合并的数据
    del_target_by_ids(del_ids)
    # 插入最新的数据
    save_target(latest[latest["id"].isin(event["id"])])

    return latest


if __name__ == '__main__':
    d = ori_batch_query(2)

    while len(d) > 0:
        r = load_latest_target()
        merge(d, r)

        d = ori_batch_query(2)
 

SQL中的时间段合并通常涉及到对时间字段进行分组并聚合,以便合并那些相邻的时间段或者填充缺失的时间点。这种操作常见于日志分析、销售数据统计等场景中,比如计算每个时间段内的总和、计数或其他汇总值。 例如,如果你有一个记录用户活动的日志表,每个记录包含用户ID、活动开始时间和结束时间,你可以通过以下步骤合并时间段: 1. **找出连续的时间段**: 使用`LAG()`函数获取前一条记录的结束时间,并与当前记录的开始时间比较,判断是否为连续时间段。 2. **创建新的时间范围字段**: 如果是连续的,创建一个新的字段表示合并后的起始时间;如果不是,添加该行到结果集中。 3. **聚集和合并数据**: 对每个合并后的时间段应用聚合函数,如SUM()用于累计某种量,COUNT()用于计数事件次数等。 4. **处理边界情况**: 可能需要特别处理第一行和最后一行,因为它们可能是单独的一段时间,而不是合并的结果。 以下是一个简单的示例查询(假设表名为`activity_logs`,有`user_id`, `start_time`, `end_time`列): ```sql WITH CTE AS ( SELECT user_id, start_time, end_time, COALESCE(LAG(end_time) OVER (PARTITION BY user_id ORDER BY start_time), start_time) + INTERVAL '1 second' as new_start_time FROM activity_logs ) SELECT user_id, MIN(new_start_time) as merged_start, MAX(end_time) as merged_end, SUM(some_quantity_column) as total_quantity FROM CTE GROUP BY user_id, DATE_TRUNC('minute', new_start_time); ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值