如何在SQL中将列分组为单独的行

时间:2017-10-01 18:30:57

标签: mysql sql database google-bigquery

我没有深刻的SQL背景,最近遇到的SQL问题似乎很难用JUST SQL。

我有一张桌子

```

IMEI | DATE | A_1 | A_2 | A_3 | B_1 | B_2 | B_3
2132 | 09/21| 2   |  4  | 4   | 5   | 2   | 4
4535 | 09/22| 2   |  2  | 4   | 5   | 2   | 3
9023 | 09/21| 2   |  1  | 5   | 7   | 2   | 2

```

如何以某种方式对A_1A_2等的值进行分组,以便我可以实现此表。基本上,我想在表格中对某些列进行分组,并将它们放入不同的行中。

IMEI | DATE | MODULE | val_1 | val_2 | val_3
2132 | 09/21| A      |  2    | 4     | 4   
2132 | 09/21| B      |  5    | 2     | 4   
...

目标是在名称空间AB等下获取值,以便将行分成新表中的不同行。

此外,有关我在哪里可以改进我的SQL的任何建议。我应该保留哪些书作为参考或我应该使用的任何其他资源?

谢谢!

2 个答案:

答案 0 :(得分:3)

您可以使用UNION

执行此操作
SELECT IMEI, DATE, 'A' AS MODULE, A_1 AS val_1, A_2 AS val_2, A_3 AS val_3
FROM   myTable

UNION ALL

SELECT IMEI, DATE, 'B', B_1, B_2, B_3
FROM   myTable

sqlfiddle上查看。

但实际上,您应该将数据存储在上述查询创建的表单中,然后使用JOIN在需要时创建原始格式。

答案 1 :(得分:2)

我喜欢玩这样的数据和问题!
以下可以被认为是过度工程,但我认为,如果您事先不知道您的列名,但有一个您描述的模式,或者它只是用于学习,看起来像您正在寻找改进你的SQL(基于这个问题的标记我假设你的意思是BigQuery SQL)

#standardSQL
WITH parsed AS (
  SELECT IMEI, DATE, 
    REGEXP_REPLACE(SPLIT(row, ':')[OFFSET(0)], r'^"|"$', '') key, 
    REGEXP_REPLACE(SPLIT(row, ':')[OFFSET(1)], r'^"|"$', '') value
  FROM `yourTable` t, 
  UNNEST(SPLIT(REGEXP_REPLACE(to_json_string(t), r'[{}]', ''))) row
),
grouped AS (
  SELECT 
    IMEI, DATE, 
    REGEXP_EXTRACT(key, r'(.*)_') MODULE, 
    ARRAY_AGG(value ORDER BY CAST(REGEXP_EXTRACT(key, r'_(.*)') AS INT64)) AS vals
  FROM parsed
  WHERE key NOT IN ('IMEI', 'DATE')
  GROUP BY IMEI, DATE, MODULE
)
SELECT IMEI, DATE, MODULE, 
  vals[SAFE_OFFSET(0)] AS val_1,
  vals[SAFE_OFFSET(1)] AS val_2,
  vals[SAFE_OFFSET(2)] AS val_3,
  vals[SAFE_OFFSET(3)] AS val_4
FROM grouped
-- ORDER BY IMEI, DATE, MODULE

您可以使用问题中的虚拟数据进行测试/播放

  
#standardSQL
WITH `yourTable` AS (
  SELECT 2132 IMEI, '09/21' DATE, 2 A_1, 4 A_2, 4 A_3, 5 B_1, 2 B_2, 4 B_3 UNION ALL
  SELECT 4535, '09/22', 2, 2 ,4, 5, 2, 3 UNION ALL
  SELECT 9023, '09/21', 2, 1 ,5, 7, 2, 2 
),
parsed AS (
  SELECT IMEI, DATE, 
    REGEXP_REPLACE(SPLIT(row, ':')[OFFSET(0)], r'^"|"$', '') key, 
    REGEXP_REPLACE(SPLIT(row, ':')[OFFSET(1)], r'^"|"$', '') value
  FROM `yourTable` t, 
  UNNEST(SPLIT(REGEXP_REPLACE(to_json_string(t), r'[{}]', ''))) row
),
grouped AS (
  SELECT 
    IMEI, DATE, 
    REGEXP_EXTRACT(key, r'(.*)_') MODULE, 
    ARRAY_AGG(value ORDER BY CAST(REGEXP_EXTRACT(key, r'_(.*)') AS INT64)) AS vals
  FROM parsed
  WHERE key NOT IN ('IMEI', 'DATE')
  GROUP BY IMEI, DATE, MODULE
)
SELECT IMEI, DATE, MODULE, 
  vals[SAFE_OFFSET(0)] AS val_1,
  vals[SAFE_OFFSET(1)] AS val_2,
  vals[SAFE_OFFSET(2)] AS val_3,
  vals[SAFE_OFFSET(3)] AS val_4
FROM grouped
ORDER BY IMEI, DATE, MODULE

输出如下

Row IMEI    DATE    MODULE  val_1   val_2   val_3   val_4    
1   2132    09/21   A       2       4       4       null     
2   2132    09/21   B       5       2       4       null     
3   4535    09/22   A       2       2       4       null     
4   4535    09/22   B       5       2       3       null     
5   9023    09/21   A       2       1       5       null     
6   9023    09/21   B       7       2       2       null