How to Pivot table in BigQuery
Update 2020:
Just call fhoffa.x.pivot()
, as detailed in this post:
- https://medium.com/@hoffa/easy-pivot-in-bigquery-one-step-5a1f13c6c710
For the 2019 example, for example:
CREATE OR REPLACE VIEW `fh-bigquery.temp.a` AS (
SELECT * EXCEPT(SensorName), REGEXP_REPLACE(SensorName, r'.*/', '') SensorName
FROM `data-sensing-lab.io_sensor_data.moscone_io13`
);
CALL fhoffa.x.pivot(
'fh-bigquery.temp.a'
, 'fh-bigquery.temp.delete_pivotted' # destination table
, ['MoteName', 'TIMESTAMP_TRUNC(Timestamp, HOUR) AS hour'] # row_ids
, 'SensorName' # pivot_col_name
, 'Data' # pivot_col_value
, 8 # max_columns
, 'AVG' # aggregation
, 'LIMIT 10' # optional_limit
);
Update 2019:
Since this is a popular question, let me update to #standardSQL and a more general case of pivoting. In this case we have multiple rows, and each sensor looks at a different type of property. To pivot it, we would do something like:
#standardSQL
SELECT MoteName
, TIMESTAMP_TRUNC(Timestamp, hour) hour
, AVG(IF(SensorName LIKE '%altitude', Data, null)) altitude
, AVG(IF(SensorName LIKE '%light', Data, null)) light
, AVG(IF(SensorName LIKE '%mic', Data, null)) mic
, AVG(IF(SensorName LIKE '%temperature', Data, null)) temperature
FROM `data-sensing-lab.io_sensor_data.moscone_io13`
WHERE MoteName = 'XBee_40670F5F'
GROUP BY 1, 2
As an alternative to AVG()
you can try MAX()
, ANY_VALUE()
, etc.
Previously:
I'm not sure what you are trying to do, but:
SELECT NTH(1, words) WITHIN RECORD column_1, NTH(2, words) WITHIN RECORD column_2, f0_
FROM (
SELECT NEST(word) words, SUM(c)
FROM (
SELECT word, SUM(word_count) c
FROM publicdata:samples.shakespeare
WHERE word in ('brave', 'attended')
GROUP BY 1
)
)
UPDATE: Same results, simpler query:
SELECT NTH(1, word) column_1, NTH(2, word) column_2, SUM(c)
FROM (
SELECT word, SUM(word_count) c
FROM publicdata:samples.shakespeare
WHERE word in ('brave', 'attended')
GROUP BY 1
)
Update 2021:
A new PIVOT operator has been introduced into BigQuery.
Before PIVOT is used to rotate sales and quarter into Q1, Q2, Q3, Q4 columns:
product | sales | quarter |
---|---|---|
Kale | 51 | Q1 |
Kale | 23 | Q2 |
Kale | 45 | Q3 |
Kale | 3 | Q4 |
Apple | 77 | Q1 |
Apple | 0 | Q2 |
Apple | 25 | Q3 |
Apple | 2 | Q4 |
After PIVOT is used to rotate sales and quarter into Q1, Q2, Q3, Q4 columns:
product | Q1 | Q2 | Q3 | Q4 |
---|---|---|---|---|
Apple | 77 | 0 | 25 | 2 |
Kale | 51 | 23 | 45 | 3 |
Query:
with Produce AS (
SELECT 'Kale' as product, 51 as sales, 'Q1' as quarter UNION ALL
SELECT 'Kale', 23, 'Q2' UNION ALL
SELECT 'Kale', 45, 'Q3' UNION ALL
SELECT 'Kale', 3, 'Q4' UNION ALL
SELECT 'Apple', 77, 'Q1' UNION ALL
SELECT 'Apple', 0, 'Q2' UNION ALL
SELECT 'Apple', 25, 'Q3' UNION ALL
SELECT 'Apple', 2, 'Q4')
SELECT * FROM
(SELECT product, sales, quarter FROM Produce)
PIVOT(SUM(sales) FOR quarter IN ('Q1', 'Q2', 'Q3', 'Q4'))
To build list of columns dynamically use execute immediate
:
execute immediate (
select '''
select *
from (select product, sales, quarter from Produce)
pivot(sum(sales) for quarter in ("''' || string_agg(distinct quarter, '", "' order by quarter) || '''"))
'''
from Produce
);