PostgreSQL使用小时约束在两个时间戳之间获取随机值

问题描述 投票:0回答:2

使用:PostgreSQL 10.5

这个问题有点类似于:

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

answer given by @pozs解决了这个问题但不允许我约束返回的随机时间戳内的小时数。我想说这是对这个问题的延伸。

任务

不同之处在于我需要在两个时间戳之间获得一个随机时间戳,但输出值中的小时必须介于10:00:0018:00:00之间。

我的尝试

我一直在尝试有效地做到这一点,但是现在只想出了存储不同部分的想法:日期,时间和毫秒,然后使用ORDER BY random() LIMIT 1将它们与3个选择相结合。然而,这远非一个快速的解决方案。

tmp_data持有日期,tmp_time持有时间,tmp_ms持有miliseconds,我使用函数加在一起以获得正确的输出:

  (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个选择预先计算的表和排序(并且需要为每一行计算)。

样本数据/说明

给定时间限制:

  • start_timestamp => 2016-01-01 10:00:00
  • end_timestamp => 2017-12-31 18:00:00

让我们根据每个部分生成随机时间戳,但是小时(小时必须在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之间,但时间戳的每个其他部分都是随机的。

random postgresql-10 sql-timestamp
2个回答
1
投票

将输出从this answer转换为date类型,然后添加10:00:00时间(较低小时约束)和random间隔最多8小时(小时上限约束)这样做非常快:

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

0
投票

如果使用EXTRACT(epoch FROM <YOUR TIMESTAMP>)将时间戳转换为秒,则可以执行以下操作:

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

查询

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

© www.soinside.com 2019 - 2024. All rights reserved.