繁体   English   中英

如何更有效地生成时间序列 SQL 数据的每个时间段的绘图行数?

[英]How to generate plot row count per time period of time series SQL data in plotly more efficiently?

我有一个包含两列日期时间和值的时间序列表。 我想生成一个行数与时间段的图表。

因此,我使用开始日期和结束日期之间的循环和SELECT COUNT(*) 每次迭代将时间段增加 30 分钟,并将计数保存到本地数组,然后绘制在散点图上。

它运作良好。 但我觉得循环中的 SQL 查询设计不佳,因为快速重复查询会打击数据库。

有没有更好的办法 ? 可能在 SQL 引擎中实现循环(在这种情况下为 postgres)? 或者是否有一个神奇的 SQL“行数与时间”实用程序?

我还为 ClickHouseDB 时间序列表实现了相同的功能。

# Y M D
start_date = dt.datetime(2022, 7, 5)
  
# to Y M D
end_date = dt.datetime(2022, 7, 8)
  
# delta time
delta = dt.timedelta(minutes=30)
  
y = []
x = []
# iterate over range of dates
while (start_date <= end_date):
    time_to = start_date + delta
    queryStr = f'''select '{start_date.strftime("%Y-%m-%d %H:%M:%S")}' as date, count(*) as count from my_packet_table 
                 WHERE datetime 
                 BETWEEN '{start_date.strftime("%Y-%m-%d %H:%M:%S")}'  
                 AND     '{time_to.strftime("%Y-%m-%d %H:%M:%S")}'  '''
    result = pd.read_sql_query(queryStr, cnx) #.to_dict()
    start_date += delta
    if (len(result)) > 0:
        y.append(int(result.iloc[0][1]))
        x_date = dt.datetime.strptime( result.iloc[0][0], "%Y-%m-%d %H:%M:%S")
        x.append(x_date )

scatter = plotly.graph_objs.Scatter(x=x, y=y, mode = 'markers+lines')
layout = plotly.graph_objs.Layout(xaxis={'type': 'date', 
                                         'tick0': x[0], 
                                         'tickmode': 'linear', 
                                         'dtick': 86400000.0 / 12 }) # 2 hrs
fig = plotly.graph_objs.Figure(data=[scatter], layout=layout)
plotly.offline.iplot(fig)

结果图如下所示。 标题:'按日期/时间每 30 分钟时间段接收的数据包数' 在此处输入图像描述

这是一个快速的答案,可以让你得到你想要的(我认为)。

这样做的唯一危险是,如果在 30 分钟间隔内有 0 行,您将不会得到一行。 解决这个问题的方法是使用 datepine,它更复杂,需要您使用GENERATE_SERIES()

由于您似乎有足够的数据,因此每个插槽至少有 1 行,因此您可以采用一种更简单的方法来截断日期,然后进行GROUP BY聚合。

像这样的查询:

/* if you know that timeslices won't have zero counts, then you can date_trunc and aggregate */
WITH TRUNCATED AS (
  SELECT date_trunc('hour', "POSITION_DATE") AS hour_stump, 
    (extract(minute FROM "POSITION_DATE"):: int / 30) AS minute_slot, * 
  FROM posdata
), 
COMBINED_STAMP AS (
  SELECT hour_stump + (minute_slot || ' minutes'):: interval AS my_interval, * 
  FROM TRUNCATED
) 
SELECT 
  my_interval, count(1) AS obs_count
FROM COMBINED_STAMP 
GROUP BY my_interval 
ORDER BY my_interval;

如果这不起作用,那是因为我没有数据来正确测试它。 我使用了以毫秒为单位的 F1 赛车数据,所以我在精神上试图调整我的查询以适应你 30 分钟的情况。

如果它不起作用,请添加一些示例数据,我可以继续提供帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM