Reputation: 5314
I would like to do some operations with numbers stored in Postgresql 9.4 JSON
format. Suppose I have this table:
CREATE TABLE t (id SERIAL, a JSON);
INSERT INTO t (a)
VALUES ('[[0.1, 2.0], [0.3, 4.0], [0.5, 6.0]]'),
('[[0.7, 8.0], [0.9, 10.0]]');
So I can decompose that with e.g. json_array_elements()
:
SELECT id, json_array_elements(a) AS sub1 FROM t;
id | sub1
----------------
1 | [0.1, 2.0]
1 | [0.3, 4.0]
1 | [0.5, 6.0]
2 | [0.7, 8.0]
2 | [0.9, 10.0]
Note, that the number of elements may vary. Now I would like to do some calculations with the sub-elements, like:
SELECT id,
((json_array_elements(a)->>0)::FLOAT) *
((json_array_elements(a)->>1)::FLOAT) as result
FROM t
However I get the error: ERROR: functions and operators can take at most one set argument
. Any hints?
Upvotes: 1
Views: 130
Reputation: 111
If version of PostgreSQL is equal or more than 10 this code from current question, do not cause error. I made fiddle with this.
CREATE TABLE t (id SERIAL, a JSON);
INSERT INTO t (a)
VALUES ('[[0.1, 2.0], [0.3, 4.0], [0.5, 6.0]]'),
('[[0.7, 8.0], [0.9, 10.0]]');
SELECT id,
((json_array_elements(a)->>0)::FLOAT) *
((json_array_elements(a)->>1)::FLOAT) as result
FROM t;
Upvotes: 0
Reputation: 36244
Use an (implicit) LATERAL
join instead:
SELECT id, (e->>0)::float * (e->>1)::float as result
FROM t, json_array_elements(a) e
Set-returning functions in the SELECT
works very special in PostgreSQL:
The exact reason of your error is that, you tried to multiply two sets (which is not allowed). PostgreSQL can calculate <element> * <element>
(will be single value), <set> * <element>
(or vice versa; will be set-valued), but not <set> * <set>
.
Upvotes: 3
Reputation: 1787
That's because json_array_elements()
returns setof json.
You should better access elements by path, like this:
SELECT
id,
(a#>>'{0,0}')::float * (a#>>'{0,1}')::float as result
FROM processing.t;
And about error is here.
If this is not an option, you can use a subquery:
select
id,
(a->>0)::float * (a->>1)::float as result
from (
SELECT
id,
json_array_elements(a) as a
FROM processing.t
) t;
In this case you are able to write expressions the way you wanted to.
Upvotes: 1