Flatten BigQuery String, который напоминает массив - PullRequest
1 голос
/ 16 мая 2019

Я работаю на стандартном диалекте BigQuery SQL.

У меня есть столбец, который, как я знаю, является массивом словарей JSON.

Длина массива варьируется от строки к строке.

Я бы хотел сгладить это, чтобы иметь доступ к элементам JSON для каждого словаря в массивах.

Например, допустим, у меня есть две записи. Первый имеет id из 1, а в столбце JSON этот

[
    {"key1":"val1a", "key2": "val1b"},
    {"key1":"val1c", "key2": "val1d"}
]

Второй имеет id из 2, а в столбце JSON -

[{"key1":"val2a", "key2":"val2b"}]

Моя цель

id | key1  | key2  | offset
---------------------------
1  | val1a | val1b |   1
1  | val1c | val1d |   2
2  | val2a | val2b |   1

(хотя я мог бы жить без смещенного столбца)

Кажется, что-то подобное может сработать ...

WITH table AS (
SELECT 1 as id,['{"key1":"val1a", "key2": "val1b"}','{"key1":"val1c", "key2": "val1d"}'] as array_column
UNION ALL
SELECT 2 as id,['{"key1":"val2a", "key2":"val2b"}'] as array_column)

SELECT id,
    json_extract_scalar(flattened_array, '$.key1') as key1,
    json_extract_scalar(flattened_array, '$.key2') as key2
FROM table t 
CROSS JOIN UNNEST(t.array_column) AS flattened_array

И фактически, этот запрос возвращает ожидаемую таблицу (за исключением столбца смещения, который тривиально добавить)

Проблема в том, что BigQuery не понимает, что это массив JSON-подобных строк. Он думает, что все это одна большая нить, и я не знаю, как убедить это иначе. Редактирование моего примера для симуляции этого смешения типов демонстрирует проблему:

WITH table AS (
SELECT 1 as id,'[{"key1":"val1a", "key2": "val1b"},{"key1":"val1c", "key2": "val1d"}]' as array_column
UNION ALL
SELECT 2 as id,'[{"key1":"val2a", "key2":"val2b"}]' as array_column)

SELECT id,
    json_extract_scalar(flattened_array, '$.key1') as key1,
    json_extract_scalar(flattened_array, '$.key2') as key2
FROM table t 
CROSS JOIN UNNEST(t.array_column) AS flattened_array

Здесь валидатор жалуется, потому что Значения, указанные в UNNEST, должны быть массивами. UNNEST содержит выражение типа STRING в [29:23]

И теперь мы в центре этой проблемы. Есть ли какой-то очевидный способ заставить BigQuery понять, что эта строка является допустимым массивом словарей JSON? Может быть, какая-то JSON_* функция, которую я пропустил, сгладит массив? Или каким-то образом CAST эта вещь в массиве?

Ответы [ 2 ]

1 голос
/ 16 мая 2019

Ниже для BigQuery Standard SQL, и я рекомендую использовать его в случае, если ваш json так же прост, как в вашем примере

#standardSQL
SELECT id, key1, key2
FROM table,
UNNEST(REGEXP_EXTRACT_ALL(array_column, r'"key1"\s*:\s*"(.*?)"')) key1 WITH OFFSET
JOIN UNNEST(REGEXP_EXTRACT_ALL(array_column, r'"key2"\s*:\s*"(.*?)"')) key2 WITH OFFSET
USING (OFFSET)

Вы можете проверить, поиграть с выше, используя пример данных из вашего вопроса, как в примере ниже

#standardSQL
WITH table AS (
  SELECT 1 AS id,'[{"key1":"val1a", "key2": "val1b"},{"key1":"val1c", "key2": "val1d"}]' AS array_column UNION ALL
  SELECT 2 AS id,'[{"key1":"val2a", "key2":"val2b"}]' AS array_column
)
SELECT id, key1, key2
FROM table,
UNNEST(REGEXP_EXTRACT_ALL(array_column, r'"key1"\s*:\s*"(.*?)"')) key1 WITH OFFSET
JOIN UNNEST(REGEXP_EXTRACT_ALL(array_column, r'"key2"\s*:\s*"(.*?)"')) key2 WITH OFFSET
USING (OFFSET)

с результатом

Row id  key1    key2     
1   1   val1a   val1b    
2   1   val1c   val1d    
3   2   val2a   val2b   

Не уверен на 100%, но я чувствую, что выше это дешевле, чем UDF - что по-прежнему отличный вариант: o) особенно для более общих случаев с более сложным json

1 голос
/ 16 мая 2019

Вы можете использовать пользовательские функции BigQuery JavaScript для анализа JSON любым удобным вам способом:

CREATE TEMP FUNCTION flatten_array(array_column STRING)
RETURNS ARRAY<STRUCT<key1 STRING, key2 STRING>>
LANGUAGE js
AS """
  return JSON.parse(array_column)
""";

WITH table AS (
SELECT 1 as id,'[{"key1":"val1a", "key2": "val1b"},{"key1":"val1c", "key2": "val1d"}]' as array_column
UNION ALL
SELECT 2 as id,'[{"key1":"val2a", "key2":"val2b"}]' as array_column)

SELECT id,
    key1,
    key2
FROM table t 
CROSS JOIN UNNEST(flatten_array(array_column)) AS flattened_array

enter image description here

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...