I know I'm probably just thinking about this wrong. I have the following structure:
CREATE TABLE mytable (
id serial PRIMARY KEY
, employee text UNIQUE NOT NULL
, data jsonb
);
And the following data:
INSERT INTO mytable (employee, data)
VALUES
('Jim', '{"sales": [{"value": 10, "yr": "2010"}, {"value": 5, "yr": "2011"}, {"value": 40, "yr": "2012"}]}'),
('Rob', '{"sales": [{"value": 10, "yr": "2009"}, {"value": 5, "yr": "2010"}, {"value": 41, "yr": "2011"}]}')
I'm trying to return all the employees and the "value" of their sales in 2012. If there is no sales in 2012 then return "No Data". I have:
SELECT id, employee,
coalesce((SELECT s.value AS value FROM mytable, jsonb_to_recordset(mytable.data->'sales') AS s(yr text, value float)
WHERE s.yr='2012'), 0) AS b FROM mytable
I get:
id |employee |b
53 |Jim |40
54 |Rob |40
The value is wrong for 'Rob'. It should be 'No Data'. (I am using 0 as the 2nd parameter for coalesce as I get an error "invalid input syntax for type double precision: 'No Data'"
The key element is to use LEFT JOIN LATERAL
instead of the implicit CROSS JOIN LATERAL
as which the short notation with just a comma is interpreted.
What is the difference between LATERAL and a subquery in PostgreSQL?
Call a set-returning function with an array argument multiple times
The query can simply be:
SELECT t.id, t.employee, s.*
FROM mytable t
LEFT JOIN LATERAL jsonb_to_recordset(t.data->'sales')
AS s(yr int, value int) ON s.yr = 2012;
We can conveniently pick sales with yr = 2012
right away without losing employees from the result.
To prettify with 'NO Data' the value
column must be a matching string type:
SELECT t.id, t.employee
, COALESCE(s.yr, 2012) AS yr
, COALESCE(s.value, 'No Data') AS value
FROM mytable t
LEFT JOIN LATERAL jsonb_to_recordset(t.data->'sales')
AS s(yr int, value text) ON s.yr = 2012;
Building on these missing (likely) details:
empoyee
is UNIQUE NOT NULL
.Each employee can have 0-n years of sales in data
- data
can be NULL.
yr
and value
store valid integer numbers. Else adapt the type.
Proper table definition:
CREATE TABLE mytable (
id serial PRIMARY KEY
, employee text UNIQUE NOT NULL
, data jsonb
);
LATERAL JOIN
?As per request in comment, these links should help, especially the first for beginners: