在没有时区的时间戳的字段上加入没有时区的 generate_series 时间戳时遇到问题

Posted

技术标签:

【中文标题】在没有时区的时间戳的字段上加入没有时区的 generate_series 时间戳时遇到问题【英文标题】:Trouble joining generate_series timestamp without time zone on a field that's timestamp without timezone 【发布时间】:2019-10-10 19:13:11 【问题描述】:

我正在尝试找出一种方法来报告有多少人同时在一个位置,精确到秒。 我有一张桌子,上面有这个人的 ID、他们输入的日期、他们输入的时间、他们离开的日期和他们离开的时间。 示例:

select unique_id, start_date, start_time, end_date, end_time
from My_Table
where start_date between '09/01/2019' and '09/02/2019'
limit 3

"unique_id" "start_date"    "start_time"    "end_date"  "end_time"
989179  "2019-09-01"    "06:03:13"  "2019-09-01"    "06:03:55"
995203  "2019-09-01"    "11:29:27"  "2019-09-01"    "11:30:13"
917637  "2019-09-01"    "11:06:46"  "2019-09-01"    "11:06:59"

我已将 start_date 和 start_time 以及 end_date 和 end_time 连接起来,因此它们是 2 个字段

select unique_id, ((start_date + start_time)::timestamp without time zone) as start_date, 
((end_date + end_time)::timestamp without time zone) as end_date

结果示例:

"start_date"
"2019-09-01 09:28:54"

所以我将其设为 CTE,然后使用第二个 CTE,该 CTE 在日期到第二个之间使用 generate_series。

目标是,生成系列在两个日期之间的每一秒都会有一行。然后当我加入我的数据集时,我可以计算 my_table 中存在多少条记录,其中 start_date(plus time) 等于或大于 generate_series date_time 字段,end_date(plus time) 小于或等于 generate_series date_time字段。

我觉得这比它需要的更难解释。

理论上,如果有人从 2019-09-01 00:01:01 进入房间并在 2019-09-01 00:01:03 离开,我会将该记录计入 generate_series 行 2019-09 -01 00:01:01、2019-09-01 00:01:02 和 2019-09-01 00:01:03。

当我查看数据时,我可以看到我应该在特定的高峰期返回房间里的数百人。但查询返回全 0。

这可能是我需要调整的字段格式问题吗?

这里是查询:

with CTE as (
select unique_id, ((start_date+start_time)::timestamp without time zone) as start_date, 
((end_date+end_time)::timestamp without time zone) as end_date
from My_table
where start_date between '09/01/2019' and '09/02/2019'
),
time_series as (
    select generate_series( (date '2019-09-01')::timestamp, (date '2019-09-02')::timestamp, interval '1 second') as date_time
)
/*FINAL SELECT*/
select date_time, count(B.unique_id) as NumPpl
FROM (
    select A.date_time
    FROM time_series a
)x
left join CTE b on b.start_date >= x.date_time AND b.end_date <= x.date_time
GROUP BY 1
ORDER BY 1

(partial) result screenshot

提前谢谢你

我还应该添加我对该数据库的只读访问权限,因此我无法创建函数。

【问题讨论】:

【参考方案1】:

简单版本:假设end_date 总是在start_date 之后,b.start_date &gt;= x.date_time AND b.end_date &lt;= x.date_time 永远不会为真。

加长版:generate_series() 也不需要 CTE,并且没有理由选择此 CTE 的所有列和所有行作为子查询。我还将删除原始数据的 CTE 并将其加入秒数(注意:这确实会以某种方式更改查询,因为您现在可能会考虑这些条目,其中 start_date 更早比2019-09-01。如果你不想要这个,你可以再次将你的条件添加到连接条件中。但我想这是你真正想要的)。我还删除了一些不需要的演员表。试试这个:

SELECT gs.second, COUNT(my.unique_id)
FROM generate_series('2019-09-01'::timestamp, '2019-09-02'::timestamp, interval '1 second') gs (second)
LEFT JOIN my_table my ON (my.start_date + my.start_time) <= gs.second
    AND (my.end_date + my.end_time) >= gs.second
GROUP BY 1
ORDER BY 1

【讨论】:

谢谢@Islingre 效果很好!非常感谢! 欢迎您@JasonSmith,并邀请您留下赞成票和接受;)

以上是关于在没有时区的时间戳的字段上加入没有时区的 generate_series 时间戳时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有时区干扰的情况下在树枝中渲染时间

javascript + postgres:时区和时间戳的使用

在带有/不带时区的日期或时间戳的查询中处理 generate_series()

将 Postgres 中没有时区的 DateTime 字段从中欧时间转换为 UTC

在 R 中使用 dplyr::if_else() 根据另一个变量的值更改 POSIXct 时间戳的时区

java中的XMLGregorianCalendar,没有时区