inspired by anonther question on SO (task is to change the value for priceRange in a json field) i have following setup:
create table house
(
sale json
);
insert into house (sale) values ('{"houses":[{"houseId":"house100","houseLocation": "malvern","attribute":{"colour":["white","grey"],"openForInspection":{"fromTime": "0001","toTime": "2359"}},"priceRange":null}]}')
going to the element:
select
sale,
sale->'houses',
pg_typeof(sale->'houses')
from house
results in typeof: json
so next try:
select
sale,
sale->'houses',
pg_typeof(sale->'houses'),
json_object_keys(sale->'houses')
from house
Query Error: error: cannot call json_object_keys on an array (the query before pg_typeof tells, its json)??
so next try:
select
sale,
sale->'houses',
pg_typeof(sale->'houses'),
(sale->'houses')[0]
from house
Query Error: error: cannot subscript type json because it is not an array ?? ( the error before it tells, its an array )
where is my mistake in type determination ?
playground:https://www.db-fiddle.com/f/k9vB34QJEKCPm9jC2He9Ev/0 ( tested with v10 and v13 )
To get the first element of a json array, use
sale -> 'houses' -> 0
Before PostgreSQL v14, you couldn't use subscripts with JSON at all, and even with v14, it does not work on the data type json, only on jsonb.
Related
I have a table containing a json column. The json values will look something like this:
{'john': 1, 'alex' : 4, 'harry' :2}
If I wanted to add 1 to john, how would I go about doing this?
demo:db<>fiddle
UPDATE mytable -- 6
SET mydata = jsonb_set( -- 4
mydata::jsonb, -- 1
'{john}', -- 2
((mydata ->> 'john')::int + 1)::text::jsonb -- 3
)::json; -- 5
Fetch your data. If it is of type json, cast it into type jsonb
Path to your requested element as text array
Fetch the original value. ->> operator returns type text, so to do an integer operation, you need to cast it into type int. Then add the 1. This result must be reconverted into type jsonb. Unfortunately type int cannot be cast into type jsonb directly, so take the intermediate step via type text
Use jsonb_set() to update the JSON object specified in (1)
If your column is of type json instead of jsonb, cast the result back into type json
Perform the update
I have a table named Test and in that one column (Subject) contains JSON values.
This is the query which i am using
select Name,Subject
from Test
where id =1;
And the following are the JSON values present inside table.
{
"subject":{
"Maths":"20",
"Physics":"21",
"English":"22"
},
"Staff":{
"English":"Anna",
"maths":"Rahul",
"Physics":"John"
}
}
Now my question is how to write a query to get English mark from JSON value.
Expected o/p is 22.
I am new to postgres, can any one help me in this thanks in advance
You can combine the -> and ->> operators
select Name,Subject, subject -> 'subject' ->> 'English' as english_mark
from Test
where id =1;
Alternatively use the #>> operator where you provide the path to the element you want as an array of keys:
select Name,Subject, subject #>> '{subject, English}' as english_mark
from Test
where id =1;
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;
I'm using postgres 9.6.1.
I have an "orders" table that has a column "orderData" that is type JSON.
What each record in the orderData column currently looks like:
[{"orderId":1}, {"orderId":2}, {"orderId":3}]
I'm trying to write a sql query that adds a key to the first order object in each array.
What each record in the orderData column should look like after query:
[{"orderId":1, "isFirstOrder": true}, {"orderId":2}, {"orderId":3}]
NOT WORKING ATTEMPT:
WITH order AS (
SELECT orderData
FROM orders
CROSS APPLY OPENJSON(c) s
WHERE i = 1
)
UPDATE order
SET c = JSON_MODIFY(c, 'isFirstOrder', 'true');
Any help would be greatly appreciated.
demo:db<>fiddle
UPDATE orders
SET c = jsonb_set(c, '{0}', c -> 0 || '{"isFirstOrder": true}');
c -> 0 gets the first element of your array
|| adds the new attribute
jsonb_set rewrites the elements if they exists whereas {0} locates the rewriting position within the array
Postgres JSON functions
For type json there's no function json_set. So you have to do a bit of casting around your json data into jsonb and the final result back into json:
UPDATE orders
SET c = jsonb_set(c::jsonb, '{0}', c::jsonb -> 0 || '{"isFirstOrder": true}')::json
demo:db<>fiddle
I've created a view called vReceivedEmail which includes a varchar column called RowPrimaryKeyValue. This column usually stores primary key id values, such as 567781, but every now and then has the descriptive text 'Ad hoc message'.
I've set the view up so that it only shows records that would hold the primary key values and then CAST the column as int.
SELECT CAST(Email.RowPrimaryKeyValue as int) as DetailID
FROM MessageStore.dbo.Email Email
WHERE ISNUMERIC(Email.RowPrimaryKeyValue) = 1
When I test the view, I only get records with the primary key values I expected, and when I look at the column listing for the view in the object explorer, the column is saved at the int data type.
I've then tried to apply the following WHERE clause in a separate query, referencing my saved view:
SELECT PotAcc.DetailID
FROM PotentialAccounts PotAcc
WHERE PotAcc.DetailID NOT IN (
SELECT RecEmail.DetailID
FROM vReceivedEmail RecEmail
)
...but I'm returning the following error:
Conversion failed when converting the varchar value 'Ad hoc message'
to data type int.
'Ad hoc message' is data from the column I filtered and converted to int, but I don't know how it's managing to trip up on this since the view explcitly filters this out and converts the column to int.
Since you are on SQL Server 2012, how about using try_convert(int,RowPrimaryKeyValue) is not null instead of isnumeric()?
Your view would look like so:
select try_convert(int, RowPrimaryKeyValue) as DetailID
from MessageStore.dbo.Email Email
where try_convert(int, RowPrimaryKeyValue) is not null
In SQL Server 2012 and up: each of these will return null when the conversion fails instead of an error.
try_convert(datatype,val)
try_cast(val as datatype)
try_parse(val as datatype [using culture])
Why doesn’t isnumeric() work correctly? (SQL Spackle)
Isnumeric() can be deceiving... however I'm betting this is due to SQL Server optimization. Though your view works, that doesn't mean the outer query guarantees that only INT is returned. Instead of using a view... use a CTE and try it. And since you are on 2012, this can all be avoided how SqlZim explained above.
WITH CTE AS(
SELECT CAST(Email.RowPrimaryKeyValue as int) as DetailID
FROM MessageStore.dbo.Email Email
WHERE ISNUMERIC(Email.RowPrimaryKeyValue) = 1)
SELECT PotAcc.DetailID
FROM PotentialAccounts PotAcc
WHERE PotAcc.DetailID NOT IN (
SELECT RecEmail.DetailID
FROM CTE RecEmail
)