SQL: как поворачивать строки в зависимости от их значения - PullRequest
0 голосов
/ 05 июля 2018

Я хочу преобразовать эти данные:

id  value
---------
1   v1=10
1   v2=20
1   v3=30
2   v1=40

чтобы выглядеть так:

id  v1     v2     v3
---------------------------
1   10     20     30
2   40     null   null

Есть ли какое-нибудь решение для этого? Я хотел бы решить это стандарт BigQuery sql.

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Ниже несколько вариантов - все для 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   
0 голосов
/ 05 июля 2018
SELECT
  id,
  MAX(IF(name = 'v1', value, NULL)) AS v1,
  MAX(IF(name = 'v2', value, NULL)) AS v2,
  MAX(IF(name = 'v3', value, NULL)) AS v3
FROM (
  SELECT
    SPLIT(value, '=')[OFFSET(0)] AS name,
    SPLIT(value, '=')[OFFSET(1)] AS value
  FROM dataset.table
)
GROUP BY id
...