Форматирование внешних таблиц в Greenplum (PostgreSQL)

Я хочу загрузить простой файл в базу данных 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 '')

person Yevgen Yampolskiy    schedule 05.11.2012    source источник
comment
Вы SET DATESTYLE = 'YMD'; перед загрузкой CSV с COPY, но я не уверен насчет внешних таблиц. Хорошая точка зрения. Сохраняется ли действие DATESTYLE во время создания внешней таблицы? Что произойдет, если вы измените его после создания внешней таблицы?   -  person Craig Ringer    schedule 06.11.2012
comment
SET DATESTYLE также применяется для чтения из внешних таблиц. Что помогает! Спасибо. Это применяется во время выбора (после создания таблицы). Похоже, это единственный способ контролировать форматы — контролировать их глобально. - не могли бы вы опубликовать это как ответ, пожалуйста?   -  person Yevgen Yampolskiy    schedule 06.11.2012
comment
Кстати, это не относится к собственно PostgreSQL. В PostgreSQL вы должны использовать file_fdw внешнюю оболочку данных (postgresql.org/docs /current/static/file-fdw.html), так как нет CREATE EXTERNAL TABLE.   -  person Craig Ringer    schedule 07.11.2012


Ответы (2)


Оказывается, вы можете:

SET DATESTYLE = 'YMD';

перед SELECTing из таблицы. Однако это повлияет на интерпретацию всех дат, а не только дат из файла. Если вы постоянно используете однозначные даты ISO в другом месте, это будет хорошо, но это может быть проблемой, если (например) вам нужно также принимать литералы даты «D/M/Y» в том же запросе.

Это характерно для CREATE EXTERNAL TABLE GreenPlum и не применяется к стандартным SQL-оболочкам SQL/MED внешних данных, как показано ниже.


Что меня удивляет, так это то, что собственно PostgreSQL (в котором нет этой функции CREATE EXTERNAL TABLE) всегда принимает даты YYYY-MM-DD и YYYYMMDD в стиле ISO, независимо от 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 дат правильно читались из входного файла.

Вот как это работает с file_fdw SQL/MED внешней обёрткой данных PostgreSQL:

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 всегда будет принимать даты ISO для CSV, независимо от стиля даты.

Если GreenPlum этого не делает, отправьте сообщение об ошибке. Идея DateStyle изменить способ чтения внешней таблицы после ее создания безумна.

person Craig Ringer    schedule 07.11.2012

Да, ты можешь.

Вы делаете это, указывая, что поле во внешней таблице имеет текстовый тип. Затем используйте преобразование в операторе вставки. Вы также можете использовать gpload и определить преобразование. Оба решения аналогичны решению, описанному выше.

Вот простой файл с целым числом и датой, выраженной в виде года, месяца, дня, разделенных пробелом:

дата1.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
person Leonard Walstad    schedule 06.11.2012
comment
Я указал в своем вопросе, что есть способ определить поля как char, а затем проанализировать их во время загрузки, но это обходной путь, который может быть нежелательным (например, моя утилита создает внешнюю таблицу, а пользовательский код отвечает за загрузку из в постоянную таблицу). Вы не можете указать «DISTRIBUTED BY» для внешних таблиц, только для внутренних таблиц — эта опция сообщает Greenplum, как группировать вашу таблицу во время загрузки в постоянную (внутреннюю) таблицу. - person Yevgen Yampolskiy; 06.11.2012
comment
Вы также можете указать DISTRIBUTED BY для внешних таблиц, доступных для записи, но не для таблиц, используемых для чтения (как я их использовал) - person Yevgen Yampolskiy; 06.11.2012