将日期和秒数与时间戳进行比较

Compare date and seconds to timestamp

我有一个 Postgres table,它在 created_date DATE 列中存储创建的时间戳,在 created_time INT 列中存储自午夜以来的秒数。

编辑:table 在客户的生产数据库上并存储来自旧系统的数据,无法更改模式。

我想根据创建的时间戳进行选择。

在MySQL中我会写:

SELECT * FROM MyCustomers
WHERE ADDTIME(created_date,SEC_TO_TIME(created_time)) > 'sometimestampliteral'

在 PostgreSQL 中会怎样?

我可以在手册中看到示例,但它们都使用文字值而不是 table 列中的值。

只需将两者相加即可:

created_date + created_time * interval '1 second' > ?

您可以使用 make_interval() 将秒数转换为间隔,然后可以将其添加到 date 列以构建适当的 timestamp:

created_date + make_interval(secs => created_time)

虽然坚持你的设计

假设 ISO format 'somedateliteral'
因为它应该是时间戳文字,所以我将其命名为 'timestamp_literal'

SELECT *, created_date + make_interval(secs => created_time) AS created_at
FROM   mycustomers
WHERE  (created_date, created_time)
     > (date 'timestamp_literal', EXTRACT(epoch FROM time 'timestamp_literal')::int);

date 'timestamp_literal'time 'timestamp_literal' 从文字中获取相应的日期/时间部分。 (如果没有时间部分,后者会中断,而前者显然也可以使用日期文字。)

为什么?

实现"sargable"。参见:

与动态计算时间戳的解决方案相反,此查询可以使用基本的 multicolumn index:

CREATE INDEX multicolumn_created ON mycustomers (created_date, created_time);

(¹ 您 可以 创建匹配的表达式索引以使其工作...)

Postgres 可以通过 ROW 值比较 完美利用此索引。 (我上次看,MySQL 做不到。)见:

正确修复

将时间戳存储为 date + integer 通常是一个没有好处的设计错误。请改用 timestamp。您可能想切换到通常首选的 timestamptz 。参见:

  • Ignoring time zones altogether in Rails and PostgreSQL

其他答案已经提供了将 (date, integer) 转换为 timestamp 的表达式 - 您可以使用它来修复 table:

BEGIN;

-- drop all depending objects: indexes, views, ...

ALTER TABLE mycustomers
   ALTER created_date TYPE timestamp
      USING (created_date + make_interval(secs => created_time)) 
 , DROP COLUMN created_time;

ALTER TABLE mycustomers RENAME created_date TO created_at;  -- or whatever

-- recreate all depending objects: indexes, views, ...

COMMIT;

显然,采用所有使用这些列的查询。手头的查询简单地变成:

SELECT * FROM mycustomers WHERE created_at > 'somedateliteral';

db<>fiddle here