按精确值匹配 PotsgreSQL timestamptz
Match PotsgreSQL timestamptz by exact value
我正在通过 Supabase.io 使用 PostgreSQL 13.3。我有一个 table 和一个名为 modified_at 的字段,它的类型是 timestamptz:
CREATE TABLE IF NOT EXISTS knowledge_views (
id uuid NOT NULL DEFAULT uuid_generate_v4() PRIMARY KEY,
modified_at timestamp with time zone DEFAULT timezone('utc'::text, now()) NOT NULL
);
我在其中有一个条目,其中 modified_at 是:2021-09-27T20:55:25.625Z
(编辑:不是,Supabase 目前隐藏了微秒)。 None 以下语句有效:
SELECT * FROM knowledge_views WHERE modified_at = timestamptz '2021-09-27T20:55:25.625Z';
SELECT * FROM knowledge_views WHERE modified_at = '2021-09-27T20:55:25.625Z'::timestamptz;
SELECT * FROM knowledge_views WHERE modified_at = to_timestamp(1632776125.625);
SELECT * FROM knowledge_views WHERE modified_at >= to_timestamp(1632776125.625) AND modified_at <= to_timestamp(1632776125.625);
但是,如果采用最后一个查询并将 <=
的毫秒数增加一到 1632776125.626
,那么它会正确找到行:
SELECT * FROM knowledge_views WHERE modified_at >= to_timestamp(1632776125.625) AND modified_at <= to_timestamp(1632776125.626);
有没有办法 select 包含毫秒的精确 timestamptz 值的行?
如果这不可能,那么将最大毫秒值加 1 的(hacky)方法是否可靠?或者我也应该从最小值减一,例如:>= to_timestamp(1632776125.624) AND modified_at <= to_timestamp(1632776125.626)
?
** 编辑 **
使用以下显示该字段实际上以微秒精度存储:
SELECT modified_at as original, cast(extract(epoch from modified_at) * 1000000 as bigint) FROM knowledge_views;
original
int8
2021-09-27T20:55:25.625Z
1632776125625535
我意识到它之前是有效的,因为客户端没有改变时间戳值字符串,即:
supabase.from("knowledge_views").select("*").eq("modified_at", "2021-09-27T20:55:25.625535")
这在我使用时崩溃了:new Date("2021-09-27T20:55:25.625535")
减少了微秒。
我会放弃 DEFAULT timezone('utc'::text, now())
。 timestamptz
值已经存储在 UTC
中,您所做的只是以您不希望的方式转置该值:
show timezone;
TimeZone
------------
US/Pacific
create table tstz_test(id integer, tstz_fld timestamptz);
insert into tstz_test values (1, now()), (2, timezone('UTC', now()));
select * from tstz_test ;
id | tstz_fld
----+-------------------------------
1 | 2021-09-27 16:56:35.964202-07
2 | 2021-09-27 23:56:35.964202-07
select tstz_fld AT TIME ZONE 'UTC' from tstz_test ;
timezone
----------------------------
2021-09-27 23:56:35.964202
2021-09-28 06:56:35.964202
select * from tstz_test where tstz_fld = '2021-09-27 23:56:35.964202Z'::timestamptz;
id | tstz_fld
----+-------------------------------
1 | 2021-09-27 16:56:35.964202-07
所以毫秒不是问题。
I have an entry in it where the modified_at is: 2021-09-27T20:55:25.625Z
.
你怎么知道这是准确的值?我问是因为 Postgres 时间戳具有 微秒分辨率 (6 个小数位)。默认情况下不显示尾随零,但 now()
(在您的奇数列 DEFAULT
中)产生四舍五入到毫秒的时间戳的机会恰好是千分之一。基础知识:
- Ignoring time zones altogether in Rails and PostgreSQL
我的猜测是您的客户报告 时间戳四舍五入到毫秒(可能是由于不幸的设置?)。 运行 SELECT * FROM knowledge_views;
在像 default PostgreSQL interactive terminal psql
这样的理智客户端中获取实际值。然后您会发现 =
运算符按预期工作 timestamptz
.
我正在通过 Supabase.io 使用 PostgreSQL 13.3。我有一个 table 和一个名为 modified_at 的字段,它的类型是 timestamptz:
CREATE TABLE IF NOT EXISTS knowledge_views (
id uuid NOT NULL DEFAULT uuid_generate_v4() PRIMARY KEY,
modified_at timestamp with time zone DEFAULT timezone('utc'::text, now()) NOT NULL
);
我在其中有一个条目,其中 modified_at 是:2021-09-27T20:55:25.625Z
(编辑:不是,Supabase 目前隐藏了微秒)。 None 以下语句有效:
SELECT * FROM knowledge_views WHERE modified_at = timestamptz '2021-09-27T20:55:25.625Z';
SELECT * FROM knowledge_views WHERE modified_at = '2021-09-27T20:55:25.625Z'::timestamptz;
SELECT * FROM knowledge_views WHERE modified_at = to_timestamp(1632776125.625);
SELECT * FROM knowledge_views WHERE modified_at >= to_timestamp(1632776125.625) AND modified_at <= to_timestamp(1632776125.625);
但是,如果采用最后一个查询并将 <=
的毫秒数增加一到 1632776125.626
,那么它会正确找到行:
SELECT * FROM knowledge_views WHERE modified_at >= to_timestamp(1632776125.625) AND modified_at <= to_timestamp(1632776125.626);
有没有办法 select 包含毫秒的精确 timestamptz 值的行?
如果这不可能,那么将最大毫秒值加 1 的(hacky)方法是否可靠?或者我也应该从最小值减一,例如:>= to_timestamp(1632776125.624) AND modified_at <= to_timestamp(1632776125.626)
?
** 编辑 **
使用以下显示该字段实际上以微秒精度存储:
SELECT modified_at as original, cast(extract(epoch from modified_at) * 1000000 as bigint) FROM knowledge_views;
original | int8 |
---|---|
2021-09-27T20:55:25.625Z | 1632776125625535 |
我意识到它之前是有效的,因为客户端没有改变时间戳值字符串,即:
supabase.from("knowledge_views").select("*").eq("modified_at", "2021-09-27T20:55:25.625535")
这在我使用时崩溃了:new Date("2021-09-27T20:55:25.625535")
减少了微秒。
我会放弃 DEFAULT timezone('utc'::text, now())
。 timestamptz
值已经存储在 UTC
中,您所做的只是以您不希望的方式转置该值:
show timezone;
TimeZone
------------
US/Pacific
create table tstz_test(id integer, tstz_fld timestamptz);
insert into tstz_test values (1, now()), (2, timezone('UTC', now()));
select * from tstz_test ;
id | tstz_fld
----+-------------------------------
1 | 2021-09-27 16:56:35.964202-07
2 | 2021-09-27 23:56:35.964202-07
select tstz_fld AT TIME ZONE 'UTC' from tstz_test ;
timezone
----------------------------
2021-09-27 23:56:35.964202
2021-09-28 06:56:35.964202
select * from tstz_test where tstz_fld = '2021-09-27 23:56:35.964202Z'::timestamptz;
id | tstz_fld
----+-------------------------------
1 | 2021-09-27 16:56:35.964202-07
所以毫秒不是问题。
I have an entry in it where the modified_at is:
2021-09-27T20:55:25.625Z
.
你怎么知道这是准确的值?我问是因为 Postgres 时间戳具有 微秒分辨率 (6 个小数位)。默认情况下不显示尾随零,但 now()
(在您的奇数列 DEFAULT
中)产生四舍五入到毫秒的时间戳的机会恰好是千分之一。基础知识:
- Ignoring time zones altogether in Rails and PostgreSQL
我的猜测是您的客户报告 时间戳四舍五入到毫秒(可能是由于不幸的设置?)。 运行 SELECT * FROM knowledge_views;
在像 default PostgreSQL interactive terminal psql
这样的理智客户端中获取实际值。然后您会发现 =
运算符按预期工作 timestamptz
.