我有一个这样的Postgres 11表:
CREATE TABLE schema.foo_numbers (
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(),
quantity INTEGER,
category TEXT
);
它有一些数据,如:
id | created_at | quantity | category
----+------------------------+----------+----------
1 | 2020-01-01 12:00:00+00 | 2 | a
2 | 2020-01-02 17:00:00+00 | 1 | b
3 | 2020-01-01 15:00:00+00 | 6 | a
4 | 2020-01-04 09:00:00+00 | 1 | b
5 | 2020-01-05 19:00:00+00 | 2 | a
6 | 2020-01-06 23:00:00+00 | 8 | b
7 | 2020-01-07 20:00:00+00 | 1 | a
8 | 2020-01-08 04:00:00+00 | 2 | b
9 | 2020-01-09 23:00:00+00 | 1 | a
10 | 2020-01-10 19:00:00+00 | 1 | b
11 | 2020-01-11 05:00:00+00 | 1 | a
12 | 2020-01-12 21:00:00+00 | 1 | b
13 | 2020-01-13 01:00:00+00 | 1 | a
14 | 2020-01-14 18:00:00+00 | 1 | b
我还有另一个表可跟踪foo类别的某些属性:
create table schema.foo_category_properties (
id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
category TEXT NOT NULL,
some_bool BOOLEAN NOT NULL DEFAULT FALSE
);
此表的数据如下:
id | category | some_bool
----+----------+-----------
1 | a | f
2 | b | f
我需要创建一个postgres函数(通过postgREST api从应用程序逻辑中调用),对于参数$ TIMESTAMP,该函数将返回created_at <= $ TIMESTAMP的每个类别的最新记录。
[理想情况下,传入的参数将被视为时区'America / Los_Angeles'中的TIMESTAMP WITH TIME ZONE,并且该函数返回最新记录,并在相同时区显示其时间戳-但是,如果这是如果以一致的方式返回正确的数据,则不可能,并且所有时间戳都保留为UTC [在应用程序逻辑中将被偏移。]
服务器时间设置为UTC:
psql => show time zone; TimeZone ---------- UTC (1 row)
我编写的postgres函数如下:
CREATE OR REPLACE FUNCTION schema.foo_proc (end_date TEXT) RETURNS TABLE ( id INTEGER, category TEXT, quantity BIGINT, snapshot_count NUMERIC, latest_entry TIMESTAMP WITH TIME ZONE ) AS $$ #variable_conflict use_column BEGIN RETURN QUERY SELECT alias1.id, alias1.category, alias1.quantity, alias1.snapshot_count, alias2.latest_entry AS latest_entry FROM ( SELECT id, category, quantity, sum(quantity) OVER (partition by category ORDER BY created_at) AS snapshot_count FROM schema.foo_numbers ) AS alias1 INNER JOIN ( SELECT max(id) AS id, category, max(created_at AT TIME ZONE 'America/Los_Angeles') AS latest_entry from schema.foo_numbers WHERE created_at AT TIME ZONE 'America/Los_Angeles' <= to_timestamp($1', 'YYYY-MM-DD HH24:MI:SS') :: TIMESTAMPTZ AT TIME ZONE 'America/Los_Angeles' group by category order by category ) AS alias2 ON alias1.id = alias2.id INNER JOIN schema.foo_category_properties fcp ON alias2.category = fcp.category WHERE fcp.some_bool IS FALSE ORDER BY alias1.category ; END; $$ LANGUAGE plpgsql;
这里是
foo_numbers
中的数据,其时间戳已移至时区“ America / Los_Angeles”
psql=> select id, created_at at time zone 'america/los_angeles', quantity, category from schemai.foo_numbers order by created_at; id | timezone | quantity | category ----+---------------------+----------+---------- 1 | 2020-01-01 04:00:00 | 2 | a 3 | 2020-01-01 07:00:00 | 6 | a 2 | 2020-01-02 09:00:00 | 1 | b 4 | 2020-01-04 01:00:00 | 1 | b 5 | 2020-01-05 11:00:00 | 2 | a 6 | 2020-01-06 15:00:00 | 8 | b 7 | 2020-01-07 12:00:00 | 1 | a 8 | 2020-01-07 20:00:00 | 2 | b 9 | 2020-01-09 15:00:00 | 1 | a 10 | 2020-01-10 11:00:00 | 1 | b 11 | 2020-01-10 21:00:00 | 1 | a 12 | 2020-01-12 13:00:00 | 1 | b 13 | 2020-01-12 17:00:00 | 1 | a 14 | 2020-01-14 10:00:00 | 1 | b (14 rows)
参数的预期输出:
"end_date":"2020-01-07 19:00:00"
将是
id | category | quantity | snapshot_count | latest_entry ----+----------+----------+----------------+------------------------ 6 | b | 8 | 10 | 2020-01-06 15:00:00 7 | a | 1 | 11 | 2020-01-07 12:00:00 (2 rows)
但是,相同参数的实际输出是:
id | category | quantity | snapshot_count | latest_entry ----+----------+----------+----------------+------------------------ 5 | a | 2 | 10 | 2020-01-05 19:00:00+00 6 | b | 8 | 10 | 2020-01-06 23:00:00+00 (2 rows)
类似的意外结果发生在将参数转换为UTC的timestamptz时。
在我尝试过的所有变体中,返回的行均与参数边界不正确匹配。
[显然,我无法理解有关如何在PG中处理时区的信息-我已经详细阅读了官方文档以及关于SO以及在to_timestamp()函数所在的PG论坛上的一些相关问题进行了讨论,但经过反复试验仍无法获得正确的结果。
非常感谢所有指导!
我有一个Postgres 11表,如下所示:CREATE TABLE schema.foo_numbers(id始终以标识身份生成整数主键,created_at TIMESTAMP时区默认为now(),数量INTEGER,...