Как Calcite справляется с преобразованием данных?

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

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

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

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 ответа

Непосредственно отвечая на вопрос, но, возможно, связанные литералы даты объявляются с DATE ключевое слово, например, вы можете увидеть примеры в тестах в тестах Beam: один, два и в документах 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)' успешно и возвращает "Дата", но затем он преобразуется в '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 path должен работать автоматически, если я правильно понял (я предполагаю, что этот класс будет использоваться для обработки значений даты / времени). Он по-прежнему будет проходить через строки, вероятно, излишне, но он должен просто работать.

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

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

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

Другие вопросы по тегам