One of my favorite uses of JSONB functionality is to unpivot data.
Let's say you were handed a dataset with this structure where each type of bed column holds the count of units
of that kind.
CREATE TABLE housing_data (
neighborhood VARCHAR(50),
studio INTEGER,
br1 INTEGER,
br2 INTEGER,
br3 INTEGER,
br4 INTEGER
);
INSERT INTO housing_data (neighborhood, studio, br1, br2, br3, br4)
VALUES ('Downtown', 500, 800, 1000, 1200, 1500),
('Midtown', 700, 950, 1150, 1400, 1700),
('Uptown', 600, 800, 1000, 1200, 1500),
('Suburbs', 300, 450, 600, 750, 900);
For your reporting needs, you would like each bed type count to be a separate row.
Here is one of my favorite tricks for accomplishing this:
SELECT neighborhood, replace(je.key,'br','') AS bed_type, je.value::integer AS num_units
FROM housing_data AS d
CROSS JOIN jsonb_each_text( to_jsonb(d) - 'neighborhood') AS je;
The assumption here is that every column except for neighborhood is a bedroom unit count. The output is:
neighborhood | bed_type | num_units
--------------+----------+-----------
Downtown | 1 | 800
Downtown | 2 | 1000
Downtown | 3 | 1200
Downtown | 4 | 1500
Downtown | studio | 500
Midtown | 1 | 950
Midtown | 2 | 1150
Midtown | 3 | 1400
Midtown | 4 | 1700
Midtown | studio | 700
Uptown | 1 | 800
Uptown | 2 | 1000
Uptown | 3 | 1200
Uptown | 4 | 1500
Uptown | studio | 600
Suburbs | 1 | 450
Suburbs | 2 | 600
Suburbs | 3 | 750
Suburbs | 4 | 900
Suburbs | studio | 300
(20 rows)
(20 rows)
If you had more than one column that wasn't a bedroom count you could revise your subtraction, to exclude that too using revised: to_jsonb(d) - 'neighborhood' - 'other_column'
, alternatively you could use array construct to_jsonb(d) - ARRAY['neighborhood','other_column']
. This trick can also be accomplished using the hstore extension and converting a row to an hstore and using the each function of hstore.