【问题标题】:Formatting External tables in Greenplum (PostgreSQL)在 Greenplum (PostgreSQL) 中格式化外部表
【发布时间】:2012-11-05 15:07:27
【问题描述】:

我想使用外部表将纯文件加载到 Greenplum 数据库中。 我可以为时间戳/日期/时间字段指定输入格式吗? (如果你知道PostgreSQL的答案,也请回复)

例如,对于 Oracle,我可以使用 DATE_FORMAT DATE MASK 'YYYYMMDD' 来告诉如何解析日期。对于 Netezza,我可以指定 DATESTYLE 'YMD'。对于 Greenplum,我找不到答案。我可以将字段描述为 char,然后在加载期间解析它们,但这是一个丑陋的解决方法。

这是我的暂定代码:

CREATE EXTERNAL TABLE MY_TBL (X date, Y time, Z timestamp ) 
LOCATION (
 'gpfdist://host:8001/file1.txt',
 'gpfdist://host:8002/file2.txt'
) FORMAT 'TEXT' (DELIMITER '|' NULL '')

【问题讨论】:

  • 在使用 COPY 加载 CSV 之前,您是 SET DATESTYLE = 'YMD';,但我不确定外部表。好点子。 DATESTYLE 在创建外部表时是否有效?如果在创建外部表后更改它会发生什么?
  • SET DATESTYLE 也适用于从外部表读取。这有帮助!谢谢你。它适用于选择期间(创建表后)。看起来这是控制格式的唯一方法 - 全局控制它们。 -- 你能把它作为答案发布吗?
  • 顺便说一句,这并不真正适用于 PostgreSQL。在 PostgreSQL 中,您将使用 file_fdw 外部数据包装器 (postgresql.org/docs/current/static/file-fdw.html),因为没有 CREATE EXTERNAL TABLE

标签: database postgresql greenplum


【解决方案1】:

看来你可以:

SET DATESTYLE = 'YMD';

SELECTing 之前。但是,这将影响所有日期的解释,而不仅仅是文件中的那些。如果您始终在其他地方使用明确的 ISO 日期,那会很好,但如果(例如)您还需要在同一查询中接受“D/M/Y”日期文字,则可能会出现问题。

这是 GreenPlum 的 CREATE EXTERNAL TABLE 特有的,不适用于 SQL 标准的 SQL/MED 外部数据包装器,如下所示。


令我惊讶的是,PostgreSQL 本身(没有 CREATE EXTERNAL TABLE 功能)总是接受 ISO 样式的 YYYY-MM-DDYYYYMMDD 日期,而与 DATESTYLE 无关。观察:

regress=> SELECT '20121229'::date, '2012-12-29'::date, current_setting('DateStyle');
    date    |    date    | current_setting 
------------+------------+-----------------
 2012-12-29 | 2012-12-29 | ISO, MDY
(1 row)

regress=> SET DateStyle = 'DMY';
SET
regress=> SELECT '20121229'::date, '2012-12-29'::date, current_setting('DateStyle');
    date    |    date    | current_setting 
------------+------------+-----------------
 2012-12-29 | 2012-12-29 | ISO, DMY
(1 row)

...因此,如果 GreenPlum 的行为方式相同,则无需执行任何操作即可从输入文件中正确读取这些 YYYYMMDD 日期。

这是它如何与 PostgreSQL file_fdw SQL/MED foreign data wrapper 一起工作:

CREATE EXTENSION file_fdw;

COPY (SELECT '20121229', '2012-12-29') TO '/tmp/dates.csv' CSV;

SET DateStyle = 'DMY';

CREATE SERVER csvtest FOREIGN DATA WRAPPER file_fdw;

CREATE FOREIGN TABLE csvtest (
    date1 date,
    date2 date
) SERVER csvtest OPTIONS ( filename '/tmp/dates.csv', format 'csv' );

SELECT * FROM csvtest ;
   date1    |   date2    
------------+------------
 2012-12-29 | 2012-12-29
(1 row)

CSV 文件内容为:

20121229,2012-12-29

因此您可以看到 Pg 将始终接受 CSV 的 ISO 日期,无论日期样式如何。

如果 GreenPlum 没有,请提交错误。 DateStyle 在创建后更改外部表的读取方式的想法很疯狂。

【讨论】:

    【解决方案2】:

    是的,你可以。

    您可以通过将外部表中的字段指定为文本类型来做到这一点。然后,在插入语句中使用转换。您还可以使用 gpload 并定义转换。两种解决方案都与上述解决方案类似。

    这是一个简单的文件,其中包含一个整数和一个以年月日表示的日期,用空格分隔:

    date1.txt

    1|2012 10 12
    2|2012 11 13
    

    启动 gpfdist:

    gpfdist -p 8010 -d ./ -l ./gpfdist.log &
    

    使用psql创建外部表、目标表、加载数据:

    psql test
    
    test=# create external table ext.t2( i int, d text ) 
      location ('gpfdist://walstl-mbp.local:8010/date1.txt') 
      format 'TEXT' ( delimiter '|' )
    ;
    
    
    test=# select * from ext.t2; i |     d      
    ---+------------
      1 | 2012 10 12
      2 | 2012 11 13
    (2 rows)
    

    现在,创建要加载数据的表:

    test=# create table test.t2 ( i int, d date ) 
    ;
    

    然后,加载表格:

    test=# insert into test.t2 select i, to_date(d,'YYYY MM DD') from ext.t2 ;
    
    test=# select * from test.t2;
     i |     d      
    ---+------------
     1 | 2012-10-12
     2 | 2012-11-13
    

    【讨论】:

    • 我在我的问题中指出,有一种方法可以将字段定义为 char,然后在加载期间对其进行解析 - 但这是一种可能不需要的解决方法(例如,我的实用程序创建外部表用户代码负责将其加载到永久表中)。您不能为外部表指定 'DISTRIBUTED BY',只能为内部表指定 - 此选项告诉 Greenplum 在加载过程中如何将您的表存储到持久(内部)表中。
    • 您也可以为可写的外部表指定 DISTRIBUTED BY,但不能为用于读取的表指定(就像我使用的那样)