我必须在其中导入数据而不包含时区信息(但是,我知道要导入的数据的具体时区),但我需要timestamp with time zone
格式数据库。一旦我导入它并将时间戳数据类型设置为timestamp with time zone
,Postgres将自动假设表中的数据来自我的时区并为其分配我的时区。不幸的是,我要导入的数据不是我的时间范围,所以这不起作用。
数据库还包含具有不同时区的数据。但是,一个表中的时区始终相同。
现在,我可以在导入数据之前将数据库的时区设置为我要导入的数据的时区(使用SET time zone
命令),并在导入后将其更改回我的时区完成后,我很确定已存储的数据不会受到数据库时区更改的影响。但这似乎是一种非常肮脏的方法,可能会在以后引起问题。
我想知道是否有一种更优雅的方式来指定导入的时区而不在数据本身中包含时区数据?
另外,我还没有找到导入后编辑时区信息的方法。有没有办法不转换,只是编辑整个表的时区,假设整个表具有相同的时区偏移(即如果在数据输入/导入时分配了错误的一个)?
编辑:
我设法在导入时指定时区,整个命令是:
set session time zone 'UTC';
COPY tbl FROM 'c:\Users\Public\Downloads\test.csv' DELIMITERS ',' CSV;
set session time zone 'CET';
然后使用会话时区导入数据。我认为这对其他连接同时对数据库的任何其他查询没有影响吗?
编辑2:
后来我发现了如何改变桌子的时区:
PostgreSQL update time zone offset
我认为在导入后更改表的时区然后使用会话临时更改本地时区更为优雅。假设整个表当然具有相同的时区。
因此,代码现在将成为以下内容:
COPY tbl FROM 'c:\Users\Public\Downloads\test.csv' DELIMITERS ',' CSV;
UPDATE tbl SET <tstz_field> = <tstz_field> AT TIME ZONE '<correct_time_zone>';
答案 0 :(得分:12)
为导入会话设置时区的效率很多比以后更新值更有效。
我的印象是你认为时区就像一个适用于表中其他方面没有变化的值的设置。但它根本不是那样的。将其视为输入/输出修饰符。实际timestamp
值(带或不带时区)始终内部存储为UTC时间戳(自'2000-01-01 00:00'
以来的秒数)。更多细节:
第二个示例中的UPDATE
会使表格的大小加倍,因为每一行都会失效并添加了新版本(这就是UPDATE
在Postgres中与MVCC一起使用的方式)。除了昂贵的操作之外,VACUUM
以后还需要做更多的工作来清理表膨胀。非常低效。
完全安全到SET
会话的本地时区。这不会以任何方式影响并发操作。顺便说一下,SET SESSION
与普通SET
相同,因为无论如何SESSION
是默认值。
如果您希望完全确定,则可以使用SET LOCAL
将设置限制为当前的交易。我引用手册here
SET LOCAL
的效果仅持续到当前结束 交易,无论是否承诺。一个特例是SET
在单个事务中按SET LOCAL
:SET LOCAL
值 看到交易结束,但之后(如果 事务已提交)SET
值将生效。
放在一起:
BEGIN;
SET LOCAL timezone = 'UTC';
COPY tabledata FROM 'c:\Users\Public\Downloads\test.csv' DELIMITERS ',' CSV;
COMMIT;
检查:
SHOW timezone;