Ниже несколько вариантов - все для BigQuery Standrad SQL
Вариант 1 - поворотное кодирование
Предположим, вы заранее знаете номер и имена столбцов для создания
В этом случае ниже делает то, что вам нужно
#standardSQL
SELECT
id,
MAX(IF(key = 'v1', val, NULL)) v1,
MAX(IF(key = 'v2', val, NULL)) v2,
MAX(IF(key = 'v3', val, NULL)) v3
FROM `project.dataset.table`,
UNNEST([STRUCT<key STRING, val STRING>(SPLIT(value,"=")[OFFSET(0)], SPLIT(value, "=")[OFFSET(1)])])
GROUP BY id
Вы можете проверить, поиграть с выше, используя фиктивные данные из вашего вопроса, как показано ниже
#standardSQL
WITH `project.dataset.table` AS (
SELECT 1 id, 'v1=10' value UNION ALL
SELECT 1, 'v2=20' UNION ALL
SELECT 1, 'v3=30' UNION ALL
SELECT 2, 'v1=40'
)
SELECT
id,
MAX(IF(key = 'v1', val, NULL)) v1,
MAX(IF(key = 'v2', val, NULL)) v2,
MAX(IF(key = 'v3', val, NULL)) v3
FROM `project.dataset.table`,
UNNEST([STRUCT<key STRING, val STRING>(SPLIT(value,"=")[OFFSET(0)], SPLIT(value, "=")[OFFSET(1)])])
GROUP BY id
-- ORDER BY id
результат, как и ожидалось:
Row id v1 v2 v3
1 1 10 20 30
2 2 40 null null
Вариант 2 - динамическое вращение
В случае, если вы не знаете количество и названия столбцов - сначала вам нужно будет сгенерировать скрипт, аналогичный приведенному выше, вариант # 1
Вам нужно бежать ниже, чтобы получить
#standardSQL
SELECT CONCAT('SELECT id, ',
STRING_AGG(
CONCAT('MAX(IF(key = "', key, '", val, NULL)) as ', key)
)
,' FROM `project.dataset.table`, UNNEST([STRUCT<key STRING, val STRING>(SPLIT(value, "=")[OFFSET(0)], SPLIT(value, "=")[OFFSET(1)])]) GROUP BY id')
FROM (
SELECT SPLIT(value, '=')[OFFSET(0)] key
FROM `project.dataset.table`
GROUP BY key
)
например, если вы запустите его против того же манекена
#standardSQL
WITH `project.dataset.table` AS (
SELECT 1 id, 'v1=10' value UNION ALL
SELECT 1, 'v2=20' UNION ALL
SELECT 1, 'v3=30' UNION ALL
SELECT 2, 'v1=40'
)
SELECT CONCAT('SELECT id, ',
STRING_AGG(
CONCAT('MAX(IF(key = "', key, '", val, NULL)) as ', key)
)
,' FROM `project.dataset.table`, UNNEST([STRUCT<key STRING, val STRING>(SPLIT(value, "=")[OFFSET(0)], SPLIT(value, "=")[OFFSET(1)])]) GROUP BY id')
FROM (
SELECT SPLIT(value, '=')[OFFSET(0)] key
FROM `project.dataset.table`
GROUP BY key
)
Вы получите ниже строки
SELECT id, MAX(IF(key = "v1", val, NULL)) AS v1,MAX(IF(key = "v2", val, NULL)) AS v2,MAX(IF(key = "v3", val, NULL)) AS v3 FROM `project.dataset.table`, UNNEST([STRUCT<key STRING, val STRING>(SPLIT(value, "=")[OFFSET(0)], SPLIT(value, "=")[OFFSET(1)])]) GROUP BY id
Итак, теперь - если вы запустите этот скрипт для своих фиктивных данных
#standardSQL
WITH `project.dataset.table` AS (
SELECT 1 id, 'v1=10' value UNION ALL
SELECT 1, 'v2=20' UNION ALL
SELECT 1, 'v3=30' UNION ALL
SELECT 2, 'v1=40'
)
SELECT id, MAX(IF(key = "v1", val, NULL)) AS v1,MAX(IF(key = "v2", val, NULL)) AS v2,MAX(IF(key = "v3", val, NULL)) AS v3 FROM `project.dataset.table`, UNNEST([STRUCT<key STRING, val STRING>(SPLIT(value, "=")[OFFSET(0)], SPLIT(value, "=")[OFFSET(1)])]) GROUP BY id
вы получите тот же результат, что и в Варианте 1, но нет, теперь для вас динамически генерируется окончательный запрос
Вариант 3 - сгладить ключ - значение против оси
Поворот это круто, но для многих практических случаев ниже простой подход оказывается очень полезным и более подходящим для работы с
#standardSQL
WITH `project.dataset.table` AS (
SELECT 1 id, 'v1=10' value UNION ALL
SELECT 1, 'v2=20' UNION ALL
SELECT 1, 'v3=30' UNION ALL
SELECT 2, 'v1=40'
)
SELECT
id,
SPLIT(value,"=")[OFFSET(0)] key,
SPLIT(value, "=")[OFFSET(1)] val
FROM `project.dataset.table`
, что дает простую ванильную структуру с выравниванием ключа
Row id key val
1 1 v1 10
2 1 v2 20
3 1 v3 30
4 2 v1 40