Estoy usando PostgreSQL 13.3 a través de Supabase.io. Tengo una tabla con un campo llamado modified_at que tiene un tipo de 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 );
Tengo una entrada donde modificó_at es: 2021-09-27T20:55:25.625Z
(editar: no lo es, Supabase actualmente oculta los microsegundos). Ninguna de las siguientes declaraciones funciona:
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);
Sin embargo, si toma la última consulta e incrementa los milisegundos de <=
en uno a 1632776125.626
, entonces encuentra correctamente la fila:
SELECT * FROM knowledge_views WHERE modified_at >= to_timestamp(1632776125.625) AND modified_at <= to_timestamp(1632776125.626);
¿Hay alguna manera de seleccionar una fila por un valor de timestamptz exacto que incluya milisegundos?
Si eso no es posible, ¿es robusto el enfoque (hacky) de agregar 1 al valor máximo de milisegundos? ¿O también debo disminuir uno del valor mínimo, por ejemplo: >= to_timestamp(1632776125.624) AND modified_at <= to_timestamp(1632776125.626)
?
** editar **
Usando lo siguiente, muestra que el campo está realmente almacenado con precisión de microsegundos:
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 | 1632776125 625 535 |
Me di cuenta de que estaba funcionando antes ya que el cliente dejó la cadena de valor de la marca de tiempo sin cambios, es decir:
supabase.from("knowledge_views").select("*").eq("modified_at", "2021-09-27T20:55:25.625535")
Esto se rompió cuando usé: new Date("2021-09-27T20:55:25.625535")
que redujo los microsegundos.
Tengo una entrada en la que se modifica_en:
2021-09-27T20:55:25.625Z
.
¿Cómo sabes que ese es el valor exacto? Lo pregunto porque las marcas de tiempo de Postgres tienen una resolución de microsegundos (6 dígitos fraccionarios). Los ceros finales no se muestran de forma predeterminada, pero la posibilidad de que now()
(en su columna impar DEFAULT
) produzca una marca de tiempo redondeada a milisegundos exactamente es de 1 en 1000. Conceptos básicos:
Supongo que su cliente informa marcas de tiempo redondeadas a milisegundos (¿tal vez debido a una configuración desafortunada?). Ejecute SELECT * FROM knowledge_views;
en un cliente cuerdo como el terminal interactivo psql
de PostgreSQL predeterminado para obtener el valor real. Luego encontrará que el operador =
funciona como se esperaba para timestamptz
.
Me desharía de la DEFAULT timezone('utc'::text, now())
. Los valores de timestamptz
ya están almacenados en UTC
, todo lo que está haciendo es transponer el valor de una manera que no desea:
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
Así que los milisegundos no son el problema.