I have a column with string entries with the following format (for example)
"[ { 'state' : 'CA', 'tax_amount' : 3},{ 'state' : 'AZ', 'tax_amount' : 4}]"
I want to sum through the tax_amounts in each entry to get a total tax amount for each row. How can I do this in PostgreSQL?
I would use a scalar sub-query:
select t.*,
(select sum((item ->> 'tax_amount')::int)
from jsonb_array_elements(t.the_column) as x(item)) as total_tax
from the_table t
Online example
You can use JSONB_POPULATE_RECORDSET() function such as
WITH t(js) AS
(
SELECT '[ { "state" : "CA", "tax_amount" : 3},
{ "state" : "AZ", "tax_amount" : 4}]'::JSONB
)
SELECT SUM(tax_amount) AS total_tax_amount
FROM t
CROSS JOIN JSONB_POPULATE_RECORDSET(NULL::record,js )
AS tab(state VARCHAR(10), tax_amount INT)
total_tax_amount
----------------
7
after fixing the syntax of the JSON object by replacing single-quotes with double-quotes, and double-quotes wrapping up whole object with single-quotes.
Demo
Related
I would like to know if there is a way i could get the size of the array of a specific node in a JSON data.
As an example, below is the JSON.
For the node 'Phone' there are two items. I would like to know the size of this node.
My objective is to parse the Java Array to a Java Array.
If i am not aware of the size of the array i would not be able to parse.
Essentially i would like to get the value "2".
{"PONumber" : 1600,
"Reference" : "ABULL-20140421",
"Requestor" : "Alexis Bull",
"User" : "ABULL",
"CostCenter" : "A50",
"ShippingInstructions" : {"name" : "Alexis Bull",
"Address": {"street" : "200 Sporting Green",
"city" : "South San Francisco",
"state" : "CA",
"zipCode" : 99236,
"country" : "United States of America"},
"Phone" : [{"type" : "Office", "number" : "909-555-7307"},
{"type" : "Mobile", "number" : "415-555-1234"}]},
"Special Instructions" : null,
"AllowPartialShipment" : true,
"LineItems" : [{"ItemNumber" : 1,
"Part" : {"Description" : "One Magic Christmas",
"UnitPrice" : 19.95,
"UPCCode" : 13131092899},
"Quantity" : 9.0},
{"ItemNumber" : 2,
"Part" : {"Description" : "Lethal Weapon",
"UnitPrice" : 19.95,
"UPCCode" : 85391628927},
"Quantity" : 5.0}]}
As an alternative, Using the below code i would get that data :
SELECT jt.phones
FROM j_purchaseorder,
JSON_TABLE(po_document, '$.ShippingInstructions'
COLUMNS
(phones VARCHAR2(100) FORMAT JSON PATH '$.Phone')) AS jt;
however if i use
SELECT jt.phones
FROM j_purchaseorder,
JSON_TABLE(po_document, '$'
COLUMNS
(ShippingInstructions VARCHAR2(100) FORMAT JSON PATH '$.ShippingInstructions')) AS jt;
i am getting the value as null.
So how can i get the entire ShippingInstructions in a single value.
For the node 'Phone' there are two items. I would like to know the size of this node.
Essentially i would like to get the value "2".
From this question and this question, you can use:
SELECT jt.phones
FROM j_purchaseorder,
JSON_TABLE(
po_document,
'$.ShippingInstructions'
COLUMNS (
phones VARCHAR2(100) FORMAT JSON WITH WRAPPER PATH '$.Phone.size()'
)
) AS jt;
Which outputs:
PHONES
[2]
If you do not want the array wrapper then you can pass the return value through JSON_VALUE:
SELECT JSON_VALUE(jt.phones, '$[0]') AS phones
FROM j_purchaseorder,
JSON_TABLE(
po_document,
'$.ShippingInstructions'
COLUMNS (
phones VARCHAR2(100) FORMAT JSON WITH WRAPPER PATH '$.Phone.size()'
)
) AS jt;
Which outputs:
PHONES
2
If you are Oracle 19c and your column is defined with an IS JSON check constraint then you can simplify the query to:
SELECT j.po_document."ShippingInstructions"."Phone".size() phones
FROM j_purchaseorder j;
Which outputs:
PHONES
2
If you are using an early Oracle version that does not support the size() function then you can get all rows and use COUNT:
SELECT COUNT(*) AS phones
FROM j_purchaseorder,
JSON_TABLE(
po_document,
'$.ShippingInstructions.Phone[*]'
COLUMNS (
phones VARCHAR2(100) FORMAT JSON PATH '$'
)
) AS jt;
Which outputs:
PHONES
2
db<>fiddle here
I have the following JSON stored in a PostgreSQL JSON column
{
"status": "Success",
"message": "",
"data": {
"serverIp": "XXXX",
"ruleId": 32321,
"results": [
{
"versionId": 555555,
"PriceID": "8abf35ec-3e0e-466b-a4e5-2af568e90eec",
"price": 550,
"Convert": 0.8922953080331764,
"Cost": 10
}
]
}
}
I would like to search for a specific priceID across the entire JSON column (name info) and select the entire results element by the PriceID.
How do i do that in postgresql JSON?
One option uses exists and json(b)_array_elements(). Assuming that your table is called mytable and that the jsonb column is mycol, this would look like:
select t.*
from mytable t
where exists (
select 1
from jsonb_array_elements(t.mycol -> 'data' -> 'results') x(elt)
where x.elt ->> 'PriceID' = '8abf35ec-3e0e-466b-a4e5-2af568e90eec'
)
In the subquery, jsonb_array_elements() unnest the json array located at the given path. Then, the where clause ensures that at least one elment in the array has the given PriceID.
If your data is of json datatype rather than jsonb, you need to use json_array_elements() instead of jsonb_array_elements().
If you want to display some information coming from the matching array element, then it is different. You can use a lateral join instead of exists. Keep in mind, though, that this will duplicate the rows if more than one array element matches:
select t.*, x.elt ->> 'price' price
from mytable t
cross join lateral jsonb_array_elements(t.mycol -> 'data' -> 'results') x(elt)
where x.elt ->> 'PriceID' = '8abf35ec-3e0e-466b-a4e5-2af568e90eec'
I'm trying to read the column which type is json, values in column look like this
column1
---------------------------------------------
"[{'name': 'Kate', 'position': 'painter'}]"
Im using this query, but all I get is null, what can I do to get the values for each keys?
SELECT
column1 ->> 'name' AS name
FROM
table1;
Then you use jsonb_pretty that Returns from_json as indented JSON text.
select jsonb_pretty('[{"name": "Kate", "position": "painter"}]');
Output display you:
jsonb_pretty
-------------------------------
[ +
{ +
"name": "Kate", +
"position": "painter"+
} +
]
so in your case you use
SELECT jsonb_pretty(column1) AS name FROM table1;
Use json_array_elements function:
SELECT json_array_elements(t) -> 'name'
FROM table1;
I want to extract data from a json type column to insert them into a table in order to normalize a database.
The JSON type column is called "info" and an example of a record is the following:
[ { "major" : "International business",
"end" : "2007",
"name" : "Annamalai University",
"degree" : "Master Degree",
"start" : "2005", "desc" : ""
},
{ "major" : "Mechanical Engineering",
"end" : "1990",
"name" : "Bharathidasan University",
"degree" : "Bachelor Degree",
"start" : "1990", "desc" : ""
}
]
This is my code:
SELECT id,
(json_array_elements(info)->>'education')::json ->> 'key' AS key1
FROM perfiles
WHERE id = 1252710;
This is the result I want to obtain:
table result example
How should I do the query?
Thanks in advance
You may use cross join lateral with json_array_elements and list the elements in the select
SELECT p.id,
j->>'major'::text AS major,
(j->>'end')::int AS "end",
j->>'name' AS NAME,
j->>'degree' AS degree,
j->>'start' AS start,
j->>'desc' AS "desc"
FROM perfiles p
CROSS JOIN LATERAL json_array_elements(info) AS j
Or use json_to_recordset by specifying column list in the FROM clause
select p.id,
j.* FROM perfiles p
cross join lateral json_to_recordset(info)
as j(major text, "end" int, name text, degree text, start int, "desc" text);
Demo
use json_to_recordset
SELECT x.*
FROM pjson_table
, json_to_recordset(myjson::json) x
( major text
, "end" text
, name text
, degree text
, start text
,"desc" text
)
demo link
major end name degree start
International business 2007 Annamalai University Master Degree 2005
Mechanical Engineering 1990 Bharathidasan University Bachelor Degree 1990
Try something like this
select *
from (
select
json_to_recordset(info) as ed(major text, end int, name text, degree text, start int, desc text)
from perfiles
where id = 1252710
)
Ref: https://www.postgresql.org/docs/9.5/functions-json.html
I am trying to remove a column from a BigQuery table and I've followed the instructions as stated here:
https://cloud.google.com/bigquery/docs/manually-changing-schemas#deleting_a_column_from_a_table_schema
This did not work directly as the column I'm trying to remove is nested twice in a struct. The following SO questions are relevant but none of them solve this exact case.
Single nested field:
BigQuery select * except nested column
Double nested field (solution has all fields in the schema enumerated, which is not useful for me as my schema is huge):
BigQuery: select * replace from multiple nested column
I've tried adapting the above solutions and I think I'm close but can't quite get it to work.
This one will remove the field, but returns only the nested field, not the whole table (for the examples I want to remove a.b.field_name. See the example schema at the end):
SELECT AS STRUCT * EXCEPT(a), a.* REPLACE (
(SELECT AS STRUCT a.b.* EXCEPT (field_name)) AS b
)
FROM `table`
This next attempt gives me an error: Scalar subquery produced more than one element:
WITH a_tmp AS (
SELECT AS STRUCT a.* REPLACE (
(SELECT AS STRUCT a.b.* EXCEPT (field_name)) AS b
)
FROM `table`
)
SELECT * REPLACE (
(SELECT AS STRUCT a.* FROM a_tmp) AS a
)
FROM `table`
Is there a generalised way to solve this? Or am I forced to use the enumerated solution in the 2nd link?
Example Schema:
[
{
"name": "a",
"type": "RECORD",
"fields": [
{
"name": "b",
"type": "RECORD"
"fields": [
{
"name": "field_name",
"type": "STRING"
},
{
"name": "other_field_name".
"type": "STRING"
}
]
},
]
}
]
I would like the final schema to be the same but without field_name.
Below is for BigQuery Standard SQL
#standardSQL
SELECT * REPLACE(
(SELECT AS STRUCT(SELECT AS STRUCT a.b.* EXCEPT (field_name)) b)
AS a)
FROM `project.dataset.table`
you can test, play with it using dummy data as below
#standardSQL
WITH `project.dataset.table` AS (
SELECT STRUCT<b STRUCT<field_name STRING, other_field_name STRING>>(STRUCT('1', '2')) a
)
SELECT * REPLACE(
(SELECT AS STRUCT(SELECT AS STRUCT a.b.* EXCEPT (field_name)) b)
AS a)
FROM `project.dataset.table`