将日期和秒数与时间戳进行比较
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
我有一个 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