Загружать данные из файла, содержащего объекты json без разделителя - PullRequest
0 голосов
/ 27 октября 2019

Я пытаюсь загрузить данные из файлов в s3 в снежинку. По независи,У меня была идея использовать '}{' и затем обернуть обе записи (объекты JSON) пропущенными скобками, но такой опции нет, и разделитель записей принимает один символ. Другим подходом может быть использование регулярного выражения для захвата одной записи, но я ничего не вижу в документах.

Есть ли лучший способ справиться с этим?

Ответы [ 2 ]

1 голос
/ 27 октября 2019

Поскольку файл в целом не является допустимым JSON, вы не можете прочитать его как полуструктурированные данные.

Вы можете прочитать файл как CSV и собрать его с небольшим умом, если объекты разделенына внутренних } символах:

CREATE OR REPLACE TABLE T (
  LINE_NO NUMBER IDENTITY,
  JSON TEXT
);

COPY INTO T(JSON) FROM (SELECT $1||'}' JSON FROM @my_stage/json.csv)
FILE_FORMAT = (TYPE = CSV FIELD_DELIMITER = NONE RECORD_DELIMITER='}');

SELECT REC_NO, PARSE_JSON(LISTAGG(JSON) WITHIN GROUP (ORDER BY LINE_NO)) JSON FROM (
  SELECT
    SUM(CASE WHEN NEW_OBJ AND MOD(QUOTE_QTY_AGG - QUOTE_QTY, 2) = 0 THEN 1 ELSE 0 END)
        OVER (ORDER BY LINE_NO) REC_NO, LINE_NO, JSON
  FROM (
    SELECT
      REGEXP_COUNT(JSON, '"') - REGEXP_COUNT(JSON, '\\\\"') QUOTE_QTY,
      SUM(REGEXP_COUNT(JSON, '"') - REGEXP_COUNT(JSON, '\\\\"'))
          OVER (ORDER BY LINE_NO) QUOTE_QTY_AGG,
      REGEXP_LIKE(JSON, '\\s*\\{\\s*".*') NEW_OBJ,
      LINE_NO, JSON
    FROM T
  )
)
GROUP BY REC_NO
ORDER BY REC_NO;

Приведенный выше запрос (высовывающий мою голову здесь) анализирует любой"допустимый" (по модулю нескольких объектов) JSON, даже такие объекты, как {"{a}": "{{b}}"}. Это достигается путем наблюдения следующего:

  • Новый объект начинается с {", но не в том случае, если { находится внутри строки
  • Начало текущей строкине внутри строки, если число неэкранированных символов в двойных кавычках в предыдущих строках равно
0 голосов
/ 28 октября 2019

Подход Ганса может работать, но это довольно (приятно!) Хак.

Существует более простой способ , если ваши файлы не слишком большие (до нескольких мегабайт).

Затем вы можете прочитать весь файл как одно значение varchar и обработать его, как показано ниже. Короче говоря, мы

  • разбиваем строку на }{
  • "исправляем" пропущенные скручивания при необходимости
  • parse_json результат:

Вот код:

create or replace table x(v varchar) as 
  select * from values('{"a":1}{"b":2}{"c":{"cc":3}}');

select parse_json(
  concat(
    iff(startswith(spl.value,'{'), '', '{'),  -- add '{' if needed 
    spl.value,
    iff(endswith(spl.value, '}'), '', '}')  -- add '}' if needed
  )
) rec 
from x, lateral split_to_table(v, '}{') spl;
-------------+
     REC     |
-------------+
 {           |
   "a": 1    |
 }           |
 {           |
   "b": 2    |
 }           |
 {           |
   "c": {    |
     "cc": 3 |
   }         |
 }           |
-------------+
...