将格式为 rfc822 的日期时间复制到 redshift

Posted

技术标签:

【中文标题】将格式为 rfc822 的日期时间复制到 redshift【英文标题】:Copy a datetime with the format rfc822 into redshift 【发布时间】:2015-09-24 09:14:51 【问题描述】:

我有以下红移表:

DROP TABLE IF EXISTS "logs";
CREATE TABLE "logs" (
  "source" varchar(255) DEFAULT NULL,
  "method" varchar(255) DEFAULT NULL,
  "path" varchar(1023) DEFAULT NULL,
  "format" varchar(255) DEFAULT NULL,
  "controller" varchar(255) DEFAULT NULL,
  "action" varchar(255) DEFAULT NULL,
  "status" integer DEFAULT NULL,
  "duration" float DEFAULT NULL,
  "view" float DEFAULT NULL,
  "db" float DEFAULT NULL,
  "ip" varchar(255)DEFAULT NULL,
  "route" varchar(255) DEFAULT NULL,
  "request_id" varchar(255) DEFAULT NULL,
  "user" INTEGER DEFAULT  NULL,
  "school" varchar(255) DEFAULT NULL,
  "timestamp" datetime DEFAULT NULL
);

到目前为止一切顺利。

唯一的问题是我在 s3 上的源文件中的日期时间如下:"2015-01-13T11:13:08.869941+00:00"。这看起来像 rfc822(或 rfc3339 或 rfc2822)。

COPY 命令支持一些时间格式(参见文档:http://docs.aws.amazon.com/redshift/latest/dg/r_DATEFORMAT_and_TIMEFORMAT_strings.html)。但不是我的 rfc822 格式。

我尝试了以下方法:

TRUNCATE logs;
COPY "logs" FROM 's3://path/to/logstash_logfile.gz'
CREDENTIALS 'aws_access_key_id=THE_KEY;aws_secret_access_key=THE_SECRET'
TIMEFORMAT AS 'MM-DD-YYYYTHH:MI:SS'
JSON 's3://path/to/jsonpath.json' GZIP;

但我得到:

SELECT * FROM stl_load_errors;

时间戳格式或值无效 [MM-DD-YYYYTHH:MI:SS]

【问题讨论】:

【参考方案1】:

请改用TIMEFORMAT 'auto'

可以导入

2015-01-13T11:13:08.869941+00:00

作为

2015-01-13 11:13:08.869941.

我假设这个方法只是丢弃了时区信息,但至少你可以通过这种方式获取数据。

如果您的数据中有不同的时区,例如,您可能需要进行一些预处理以将所有内容转换为 UTC。

不幸的是,我认为 COPY 提供的时间格式相当严格,不支持时区部分。

【讨论】:

有没有办法为这个字段指定一个转换函数? s3 上的数据很大,重新处理需要几天时间。另一种方法是导入为字符串,然后创建另一个表为select from first_table... 仍然有很多工作。 我不知道有这样的事情,但您当然可以写信给 AWS 开发人员论坛,亚马逊代表也会在论坛上回答问题。你真的有不同的时区,所以“自动”对你不利吗? Arvidaa 你是对的:这会丢弃时区信息。 @BenjaminCrouzier,请参阅下面的答案,了解您建议的解决方案。这是一些开销,但可以管理。【参考方案2】:

我们遇到了完全相同的问题并找到了解决方法:

CREATE TABLE final_table ("ts_as_timestamptz" TIMESTAMPTZ);
CREATE TEMP TABLE helper_table ("ts_as_varchar" VARCHAR(64));

COPY "helper_table" FROM 's3://path/to/file.csv.gz'
CREDENTIALS 'aws_access_key_id=THE_KEY;aws_secret_access_key=THE_SECRET'
CSV
GZIP;

INSERT INTO final_table (ts_as_timestamptz)
SELECT ts_as_varchar::TIMESTAMPTZ FROM helper_table;

或者,或者:

CREATE TABLE final_table ("ts_as_timestamp" TIMESTAMP);
CREATE TEMP TABLE helper_table ("ts_as_varchar" VARCHAR(64));

COPY "helper_table" FROM 's3://path/to/file.csv.gz'
CREDENTIALS 'aws_access_key_id=THE_KEY;aws_secret_access_key=THE_SECRET'
CSV
GZIP;

INSERT INTO final_table (ts_as_timestamp)
SELECT ts_as_varchar::TIMESTAMPTZ FROM helper_table;

你可以用这个快速测试:

DROP TABLE IF EXISTS helper_table;
CREATE TEMP TABLE helper_table ("ts_as_varchar" VARCHAR(64));
INSERT INTO helper_table (ts_as_varchar) VALUES 
    ('2015-01-13T11:13:08.869941+00:00'),
    ('2015-01-13T12:13:08.869941+01:00'),
    ('2015-01-13T13:13:08.869+02:00'), 
    ('2015-01-13T14:13:08+03:00'),
    ('2015-01-13T11:13:08'),
    ('2015-01-13 11:13:08.869941+00:00'),
    ('2015-01-13 12:13:08.869941+01:00'),
    ('2015-01-13 13:13:08.869+02:00'), 
    ('2015-01-13 14:13:08+03:00'),
    ('2015-01-13 11:13:08')
;

DROP TABLE IF EXISTS final_table;
CREATE TEMP TABLE final_table (
    "ts_as_varchar" VARCHAR(64),
    "ts_as_timestamptz" TIMESTAMPTZ,
    "ts_as_timestamp" TIMESTAMP
    );
INSERT INTO final_table (ts_as_varchar, ts_as_timestamptz, ts_as_timestamp)
SELECT ts_as_varchar, ts_as_varchar::TIMESTAMPTZ, ts_as_varchar::TIMESTAMPTZ
FROM helper_table;

-- The following depends on the time zone of your SQL client, so the results may vary. It is also vulnerable to the SQL client removing the sub-second parts.
-- SELECT * FROM final_table;
-- The following may (?) work better even if your SQL client is not in UTC
SELECT ts_as_varchar, ts_as_timestamptz::VARCHAR, ts_as_timestamp::VARCHAR
FROM final_table;

这给出了这些结果:

ts_as_varchar                       ts_as_timestamptz                ts_as_timestamp
2015-01-13T11:13:08                 2015-01-13 11:13:08+00           2015-01-13 11:13:08
2015-01-13T11:13:08.869941+00:00    2015-01-13 11:13:08.869941+00    2015-01-13 11:13:08.869941
2015-01-13T12:13:08.869941+01:00    2015-01-13 11:13:08.869941+00    2015-01-13 11:13:08.869941
2015-01-13T13:13:08.869+02:00       2015-01-13 11:13:08.869+00       2015-01-13 11:13:08.869
2015-01-13T14:13:08+03:00           2015-01-13 11:13:08+00           2015-01-13 11:13:08
2015-01-13 11:13:08                 2015-01-13 11:13:08+00           2015-01-13 11:13:08
2015-01-13 11:13:08.869941+00:00    2015-01-13 11:13:08.869941+00    2015-01-13 11:13:08.869941
2015-01-13 12:13:08.869941+01:00    2015-01-13 11:13:08.869941+00    2015-01-13 11:13:08.869941
2015-01-13 13:13:08.869+02:00       2015-01-13 11:13:08.869+00       2015-01-13 11:13:08.869
2015-01-13 14:13:08+03:00           2015-01-13 11:13:08+00           2015-01-13 11:13:08

使用 Redshift 1.0.2610 测试 请注意,您的 SQL 客户端或驱动程序可能会进行一些可能具有误导性的时区转换,因此最好使用 UTC 作为您的计算机/驱动程序/SQL 客户端的时区来进行测试。 此外,一些 SQL 客户端会删除时间戳的亚秒级部分。

【讨论】:

以上是关于将格式为 rfc822 的日期时间复制到 redshift的主要内容,如果未能解决你的问题,请参考以下文章

如何将格式稍有错误的 RFC822 字符串转换为日期?

[翻译]C#.我该如何分析和转换日期时间的到RFC 822的日期,时间格式(How do I parse and convert DateTi

Saxon XSLT 2.0 和 RFC 822 日期格式

如何在 Perl 中以 RFC822 格式优雅地打印日期?

[翻译]Convert a date to the RFC822 standard for use in RSS feeds(在RSS源中间日期转换成RFC822标准使用)

Flask 学习-72.Flask-RESTX 自定义输出日期格式