Как Calcite справляется с преобразованием данных? - PullRequest
0 голосов
/ 17 октября 2018

Я пытаюсь преобразовать дату, которая хранится в виде строки, в дату, например,

ГГГГММДД (строка) в ГГГГ-ММ-ДД (дата)

Насколько я знаюнет функции преобразования, которая проверяет формат ввода и формат вывода, я пробовал ручную логику, например,

CASE 
  WHEN CHAR_LENGTH(TRIM(some_string_date)) = 8
  THEN
    CAST(
      SUBSTRING(TRIM(some_string_date) FROM 1 FOR 4)
      || '-'
      || SUBSTRING(TRIM(some_string_date) FROM 5 FOR 2)
      ||'-'
      || SUBSTRING(TRIM(some_string_date) FROM 7 FOR 2)
    as DATE) 
  ELSE
    NULL 
END

Однако Apache SQL Validator не принимает это, кто-нибудь видит здесь проблему?

Ответы [ 2 ]

0 голосов
/ 18 октября 2018

Непосредственно не отвечая на вопрос, но может быть связано, литералы даты объявляются с ключевым словом DATE, например, вы можете увидеть примеры в тестах в тестах Beam: one , two и в Calcite документы .

Обновление:

Похоже, что Calcite добавляет некоторую косвенность при выполнении CASE.Приведение строк к датам в целом работает как положено.Например, если входные строки имеют схему (INT f_int, VARCHAR f_string), а даты в 'YYYYMMDD' (например, (1, '2018'), то это работает:

SELECT f_int,
   CAST(
    SUBSTRING(TRIM(f_string) FROM 1 FOR 4)
      ||'-'
      ||SUBSTRING(TRIM(f_string) FROM 5 FOR 2)
      ||'-'
      ||SUBSTRING(TRIM(f_string) FROM 7 FOR 2) as DATE)
  FROM PCOLLECTION

Даже непосредственное приведение 'YYYYMMDD' работает:

SELECT f_int,
   CAST(f_string AS DATE)
FROM PCOLLECTION

Здесь вы можете увидеть все поддерживаемые форматы даты здесь .

Но как только вы обернетесь в 'CASE ... ELSE NULL', Beam / Calcite, похоже, выведут, что тип выражениятеперь 'String'. Это означает, что 'THEN CAST(... AS DATE)' завершается успешно и возвращает 'Date', но затем преобразуется в 'String' при переносе в 'CASE'. Затем, при возврате результата в моем тесте, он, кажется, пытается броситьон возвращается к 'Date', но формат строки теперь не 'YYYYMMDD', а какой-то другой формат по умолчанию. К сожалению, этот формат отсутствует в списке поддерживаемых, поэтому он не работает.

Обходной путь:

Как только вы меняете 'ELSE NULL' на что-то, что известно как 'Date', например 'ELSE DATE "2001-01-01"', тогда он снова работает, так как Beam / Calcite, похоже, не идут по пути 'String'->'Date'->'String'->'Date'и это работает:

SELECT f_int,
  CASE WHEN CHAR_LENGTH(TRIM(f_string)) = 8
    THEN CAST (
       SUBSTRING(TRIM(f_string) FROM 1 FOR 4)
       ||'-'
       ||SUBSTRING(TRIM(f_string) FROM 5 FOR 2)
       ||'-'
       ||SUBSTRING(TRIM(f_string) FROM 7 FOR 2) AS DATE)
    ELSE DATE '2001-01-01'
  END
FROM PCOLLECTION

Я подал BEAM-5789 , чтобы отследить лучшее решение.

Обновление 2:

Итак, в то время как Calcite генерирует план, сообщающий Beam, что делать, именно Beam в данном случае на самом деле приводит / анализирует даты.Есть попытка использовать встроенные в Calcite реализации базовых операций вместо того, чтобы заново реализовывать все в Beam: https://github.com/apache/beam/pull/6417.После объединения этого запроса извлечения этот путь CASE ... ELSE NULL должен работать автоматически, если я правильно его читаю (я предполагаю, что этот класс будет использоваться для обработки значений даты / времени).Он по-прежнему будет проходить через строки, вероятно, излишне, но он должен просто работать.

0 голосов
/ 17 октября 2018

Если есть MYSQL.Вы можете попробовать

SELECT DATE_FORMAT(STR_TO_DATE('20080908', '%Y%m%d'), "%Y-%m-%d");

. Для проверки вы можете проверить, может ли строка быть успешно преобразована в дату.иногда.NULL означает сбой.

...