PostgreSQL 在具有小时约束的两个时间戳之间获取随机值

PostgreSQL Get random value between two timestamps with hours constraint

使用:PostgreSQL 10.5

这个问题有点类似于:

PostgreSQL Get a random datetime/timestamp between two datetime/timestamp

answer given by @pozs 解决了问题,但不允许我限制返回的随机时间戳中的小时数。 我想说这是这个问题的扩展。

任务

不同的是我需要在两个时间戳之间得到一个random时间戳,但是输出值hour =]必须介于 10:00:0018:00:00.

之间

我的尝试

我一直在努力节省时间,但现在只想到了存储以下不同部分的想法:日期、时间和毫秒,然后使用 ORDER BY random() LIMIT 1 将它们与 3 个选择结合起来.然而,这远不是一个快速的解决方案。

tmp_data 保存日期,tmp_time 保存时间,tmp_ms 保存毫秒,我使用函数将它们加在一起以获得正确的输出:

  (SELECT data FROM tmp_data ORDER BY random() LIMIT 1) 
+ (SELECT czas FROM tmp_time WHERE czas BETWEEN '10:00:00' AND '18:00:00' ORDER BY random() LIMIT 1) 
+ (SELECT ms FROM tmp_ms ORDER BY random() LIMIT 1)

这就完成了工作,但需要一些时间,因为 3 次选择了带有排序的预计算表(并且需要为每一行计算)。

样本数据/解释

鉴于时间限制:

让我们根据除小时以外的每个部分生成随机时间戳(小时必须在 10 到 18 之间)。

示例输出 - 随机生成

 2016-09-12 11:54:59.4919
 2016-01-10 10:39:03.626985
 2016-01-03 15:58:19.599016
 2016-04-11 10:05:07.527829
 2016-07-04 12:57:33.125333
 2017-12-15 14:17:46.975731
 2016-10-04 16:55:01.701048
 2016-09-26 13:36:59.71145
 2017-09-06 17:25:09.426963
 2016-09-08 17:08:00.917743

这里的每个小时都在 10 点到 18 点之间,但时间戳的其他部分是随机的。

如果您使用 EXTRACT(epoch FROM <YOUR TIMESTAMP>) 将时间戳转换为秒,您可以这样做:

  1. random() 给出一个介于 0 和 1
  2. 之间的值
  3. 如果将随机值乘以时间戳差异,您将得到可能的范围(对于 10 到 18 小时,范围将在 0 到 8 小时之间)
  4. 将起点添加到范围会将计算值移动到起点和终点之间的值。现在你有了预期的随机时间戳(以秒为单位)
  5. 使用 to_timestamp
  6. 将秒数转换回 Postgres 时间戳
  7. 这样做 2 次:一次获取随机日期,一次获取随机时间。
  8. 添加两个时间戳(一个转换为日期,一个转换为时间)。

查询

WITH timestamps AS (

    SELECT 
        EXTRACT(epoch FROM start::time) start_time,
        EXTRACT(epoch FROM "end"::time) end_time,
        EXTRACT(epoch FROM start::date) start_date,
        EXTRACT(epoch FROM "end"::date) end_date
    FROM (
        SELECT
            '2016-01-01 10:00:00'::timestamp as start,
            '2017-12-31 18:00:00'::timestamp as end
    ) s
)

SELECT 
    to_timestamp(
        random() * (ts.end_date - ts.start_date) + ts.start_date 
    )::date + 
    to_timestamp(
        random() * (ts.end_time - ts.start_time) + ts.start_time 
    )::time 
FROM timestamps ts

demo:db<>fiddle

将输出从 this answer 转换为 date 类型,然后添加 10:00:00 时间(下小时约束)和 random 最多 8 小时的间隔(上小时) constraint)做的很快:

select 
  date (timestamp '2016-01-01' + 
        random() * (timestamp '2017-12-31' - timestamp '2016-01-01'))
 + time '10:00:00' 
 + random() * INTERVAL '8 hours';