Select from JSONB field with WHERE clause - postgresql

Just installed 9.4 and trying to use JSONB field type.
I've made a table with jsonb field and able to select from it:
select statistics->'statistics'->'all_trades'->'all'->'all_trades_perc_profit' as profitable_perc FROM trade_statistics
Works fine.
Now I want to filter results based on field value:
select statistics->'statistics'->'all_trades'->'all'->'all_trades_perc_profit' as profitable_perc FROM trade_statistics WHERE profitable_perc > 1
//There is no "profitable_perc" column
Does not work.
If I try to convert result to double, does not work either.
select cast(statistics->'statistics'->'all_trades'->'all'->'all_trades_perc_profit' as double precision) as profitable_perc FROM trade_statistics
//cant convert jsonb into double precision
How should I use select results in WHERE clause in case of jsonb?

Three corrections have to be made:
Wrap the the query in a subquery - you cannot reference the SELECT list aliases in WHERE clause
Use the ->> operator to get the value as text
Cast the text value as integer so you can make the comparison
SELECT *
FROM (
SELECT (statistics->'statistics'->'all_trades'->'all'->>'all_trades_perc_profit')::integer as profitable_perc
FROM trade_statistics
) sq1
WHERE profitable_perc > 1

Related

Fetch rows from postgres table which contains a specific id in jsonb[] column

I have a details table with adeet column defined as jsonb[]
a sample value stored in adeet column is as below image
Sample data stored in DB :
I want to return the rows which satisfies id=26088 i.e row 1 and 3
I have tried array operations and json operations but it does'nt work as required. Any pointers
Obviously the type of the column adeet is not of type JSON/JSONB, but maybe VARCHAR and we should fix the format so as to convert into a JSONB type. I used replace() and r/ltrim() funcitons for this conversion, and preferred to derive an array in order to use jsonb_array_elements() function :
WITH t(jobid,adeet) AS
(
SELECT jobid, replace(replace(replace(adeet,'\',''),'"{','{'),'}"','}')
FROM tab
), t2 AS
(
SELECT jobid, ('['||rtrim(ltrim(adeet,'{'), '}')||']')::jsonb as adeet
FROM t
)
SELECT t.*
FROM t2 t
CROSS JOIN jsonb_array_elements(adeet) j
WHERE (j.value ->> 'id')::int = 26088
Demo
You want to combine JSONB's <# operator with the generic-array ANY construct.
select * from foobar where '{"id":26088}' <# ANY (adeet);

Build jsonb array from jsonb field

I have column options with type jsonb , in format {"names": ["name1", "name2"]} which was created with
UPDATE table1 t1 SET options = (SELECT jsonb_build_object('names', names) FROM table2 t2 WHERE t2.id= t1.id)
and where names have type jsonb array.
SELECT jsonb_typeof(names) FROM table2 give array
Now I want to extract value of names as jsonb array. But query
SELECT jsonb_build_array(options->>'names') FROM table
gave me ["[\"name1\", \"name2\"]"], while I expect ["name1", "name2"]
How can I get value in right format?
The ->> operator will return the value of the field (in your case, a JSON array) as a properly escaped text. What you are looking for is the -> operator instead.
However, note that using the jsonb_build_array on that will return an array containing your original array, which is probably not what you want either; simply using options->'names' should get you what you want.
Actually, you don't need to use jsonb_build_array() function.
Use select options -> 'names' from table; This will fix your issue.
jsonb_build_array() is for generating the array from jsonb object. You are following wrong way. That's why you are getting string like this ["[\"name1\", \"name2\"]"].
Try to execute this sample SQL script:
select j->'names'
from (
select '{"names": ["name1", "name2"]}'::JSONB as j
) as a;

PostgreSQL insert from SQL SELECT statement fails because of expression type text

I'm running into a simple error on PostgreSQL inserting data into a new table. I'd like to use a simple query because this table is only going to store averages across different dimensions. I want my avg column to be double precision. My insert statement is
insert into benchmark_table
(select avg(s.percentage_value) as avg, s.metric_name, s.category
from some_table s group by s.category, s.metric_name);
This command fails with the following error:
ERROR: column "avg" is of type double precision but expression is of
type text LINE 2: ...(s.percentage_value) as double precision) as avg,
s.metric_n...
^ HINT: You will need to rewrite or cast the expression.
So I try casting my avg column to double precision:
INSERT into benchmark_table
(SELECT cast(avg(s.percentage_value) as double precision) as avg, s.metric_name, s.category
FROM some_table s group by s.category, s.metric_name);
I've also attempted
insert into benchmark_table
(Select avg(s.percentage_value)::double precision as avg, s.metric_name, s.category
from summary_view_output s group by s.category, s.metric_name);
However, I get the same error about avg being text. I understand that what's being returned from my query is a result set that is by default text, but I'm not seeing any way to convert this into another datatype for my outer INSERT statement to use.
Try to change the ::double precision to ::float and see if that works. Also I noticed you aren't including the field names in the Insert clause. Maybe the ordinal position of the fields of the benchmark_table is not the same as in the select statement.
try to use.
insert into benchmark_table( avg, metric_name, category)

Parse jsonb field - PostgreSQL

I have a field that is of type jsonb in a PostgreSQL database.
Example:
{"timestamp":"2016-12-14T04:15:04.836Z","receiptResult":{"status":"successful","timestamp":"2016-12-14T04:15:04.739Z","notes":"Customer Accepted"}}
How can I only return the "notes" in a select statement, I've tried:
SELECT data::json->>'notes' as notes
But nothing is returned, if I use:
SELECT data::json->'receiptResult' as notes;
It returns:
{"status":"successful","timestamp":"2016-114T04:15:04.739Z","notes":"Customer Accepted"}
But I only need the text after "notes".
Inside key receiptResult has another JSON object, you cannot access it in top-level. Try this:
WITH sample AS (
SELECT '{"timestamp":"2016-12-14T04:15:04.836Z","receiptResult":{"status":"successful","timestamp":"2016-12-14T04:15:04.739Z","notes":"Customer Accepted"}}'::jsonb AS my_column
)
SELECT my_column->'receiptResult'->>'notes' FROM sample;
As you can see, -> operator returns value as a JSONB and ->> operator returns as a text.
More info here.

UNION ALL, cast NULL as double precision, Postgres

In postgres, I'm getting an error when I try to union two tables where one table has a column (Amount) containing double precision data type, and the other table does not have a matching column and I'd like the records from that table to just have NULL in the Amount field.
Error:
"union types text and double precision cannot be matched postgres"
Pseudo-code:
SELECT * FROM (
SELECT
t1.Amount AS 'amount',
NULL::DATE AS 'date'
FROM Table1 AS t1
UNION ALL
SELECT
/* next line is the issue */
NULL AS 'amount',
t2.Date AS 'date'
FROM Table2 AS t2
) AS FOO
I feel fairly certain this solution is a simple casting problem but could not find anything from searching. How do I do the equivalent of NULL::DOUBLE in postgres?
EDIT::POSTERITY
The accepted answer from #klin and #a_horse_with_no_name's comment that points to a "historical" postgres cast expression :: where the syntax is equivalent:
CAST ( expression AS type )
expression::type
And, here is a list of the postgres data types.
In Postgres the type double precision is also known as float8 or simply float. Use one of them.
select null::double precision, null::float;