Query json_array in where clauses by key and value - sql

I have a select query witch returns me an array_to_json object. I want to filters the results of select based on specifics keys and values.
Here is my actual query:
select jsonarray
from (
SELECT body.id_user,
array_to_json(array_agg(row_to_json(body))) as jsonarray
FROM (
SELECT id_user, name, value
FROM table_1
group by id_user, name, value
) body
group by body.id_user
) as test;
It returns a lot of rows like this:
[{"id_user": 1489, "name": "name 1", "value": "value aaaaaa"}, {"id_user": 1489, "name": "name 2", "value": "value babababab"}]
[{ "id_user": 1490, "name": "name 12", "value": "value aaaaaa" }, { "id_user": 1490, "name": "name 2", "value": "value babababab" }]
[ { "id_user": 1491, "name": "name 13", "value": "value aaaaaa" }, { "id_user": 1491, "name": "name 23", "value": "value uouououo" }]
Well, I want only the rows that have the fields "name": "name 2", "value": "value babababab" into the json... I've tried
select jsonarray->'name'
from (
....
) as test
where jsonarray->>'name'::text = 'name 2';
but it returns nothing. There's another way to query it?

You can check if name 2 is present during the aggregation:
SELECT jsonb_agg(to_jsonb(body)) as jsonarray
FROM (
SELECT DISTINCT id_user, name, value
FROM table_1
) body
group by body.id_user
having bool_or(name = 'name 2') -- those with at least one `name = 'name 2'`
Online example

Related

Loop over json value of columns of a SQL Server table

I have the return of a json in the children column of the table. How can I loop over the title values ​​present in the children column?
Example of JSON present in a table row.
[
{
"id": "5CBDE9F2-5D81-4CA9-8302-0908104558D9",
"title": "Title 1",
"Code": "5874"},
{
"id": "9BFC4A6C-9BDC-4C15-B01F-5B87683AE50F",
"title": "Title 2",
"Code": "6582"
}
]
I know using the [key] doesn't work. But like [0] or [2] I get it. How can I interact?
SELECT *
FROM vwJSONFilhos A
WHERE json_value(Filhos,'$[key].title') = 'Title 2'

Postgres Text to json

I have a column with the following text data (2 rows):
{"{john,m,25.01.1980}","{steve,m,12.12.1995}","{kate,f,17.04.1990}"}
{"{max,m,26.01.1980}","{sarah,f,18.04.1990}"}
This need to be converted into json like this (2 rows):
[{ "birth_date": 1234567890, "name": "john", "gender": "m" }, { "birth_date": 1234567890, "name": "steve", "gender": "m" }, { "birth_date": 1234567890, "name": "kate", "gender": "f" }]
[{ "birth_date": 1234567890, "name": "max", "gender": "m" }, { "birth_date": 1234567890, "name": "sarah", "gender": "f" }]
I have tried to use UNNEST, row_to_json and json_build_object, but cannot fugure out how to do this.
You can try this :
SELECT jsonb_agg(jsonb_build_object
('birth_date', split_part(left(d.data, -1), ',', 3) :: date
,'name', split_part(right(d.data, -1), ',', 1)
,'gender', split_part(d.data, ',', 2)))
FROM your_table AS t
CROSS JOIN LATERAL unnest(t.your_text_column :: text[]) AS d(data)
GROUP BY t
see the test result in dbfiddle.
here is one way:
select Id
, json_agg(json_build_object('name', split_part(jsondata, ',',1) , 'gender', split_part(jsondata, ',',2), 'birth_date', split_part(jsondata, ',' ,3))) json_info
from (
select id
, replace(replace(json_array_elements(replace(replace(info,'{"','["'), '"}','"]')::json) #>> '{}','{',''),'}','') jsondata
from tablename
) t group by id
db<>fiddle here

How to use JSON values in Oracle PL/SQL Inner Join SELECT statement

I have two tables T1 and T2. In T1 I have a column C1 that contains a value :
"businessKeys": [{
"name": "REF_ID",
"value": "2634",
"type": "Integer"
}, {
"name": "VERSION_REF_ID",
"value": "91950",
"type": "Integer"
}, {
"name": "SCENARIO",
"value": "test1",
"type": "String"
}, {
"name": "CYCLE",
"value": "2021Q3-1",
"type": "String"
}
]
In Table T2 I have a column C2 :
{
"businessKeys": [{
"name": "REF_ID",
"value": "2634",
"type": "Integer"
}, {
"name": "VERSION_REF_ID",
"value": "91950",
"type": "Integer"
}, {
"name": "SCENARIO",
"value": "test1",
"type": "String"
}, {
"name": "CYCLE",
"value": "2021Q3-1",
"type": "String"
}
],
"secondaryKeys": [{
"name": "EQUATION_ID",
"value": "Value1",
"type": "String"
}, {
"name": "EQUATION_NAME",
"value": "Value 2",
"type": "String"
}, {
"name": "USECASE",
"value": "Test Use Case",
"type": "String"
}, {
"name": "RECORD_DATE",
"value": "07-01-2023",
"type": "Date"
}, {
"name": "OUTPUT_VALUE",
"value": "0",
"type": "Float"
}
]
}
How do I get "secondaryKeys" from T2.C2 if I match "businessKeys"?
If it wasn't JSON fields I would have a simple SELECT :
SELECT t2.secondaryKeys from T1 t1, T2 t2
WHERE t1.businessKeys = t2.businessKeys
I also need to retrieve certain value from SecondaryKeys : OUTPUT_VALUE.
I assumed there's an additional column id in table t1, which you use to select a (unique?) row from t1. Notice where that goes: the where clause at the end of subquery q1 in the with clause.
This solution depends critically on the JSON structure being very rigid: the businessKeys object value is always an array with four object members with exactly those keys AND exactly those values for the key name, and similarly for secondaryKeys. These can be relaxed easily in later Oracle versions, which support filter expressions in JSON paths, the JSON_EQUAL condition, etc.; in Oracle 12.1 (and even 12.2) it would be quite a bit harder.
with
q1 (bk_ref_id, bk_version_ref_id, bk_scenario, bk_cycle) as (
select j1.bk_ref_id, j1.bk_version_ref_id, j1.bk_scenario, j1.bk_cycle
from t1 cross apply
json_table(c1, '$.businessKeys'
columns ( bk_ref_id integer path '$[0].value'
, bk_version_ref_id integer path '$[1].value'
, bk_scenario varchar2 path '$[2].value'
, bk_cycle varchar2 path '$[3].value'
)
) j1
where t1.id = 101 -------- INPUT ID GOES HERE --------
)
, q2 (bk_ref_id, bk_version_ref_id, bk_scenario, bk_cycle, sk_output_value) as (
select j2.bk_ref_id, j2.bk_version_ref_id, j2.bk_scenario, j2.bk_cycle,
j2.sk_output_value
from t2 cross apply
json_table(c2, '$'
columns
( sk_output_value number path '$.secondaryKeys[4].value'
, nested path '$.businessKeys'
columns ( bk_ref_id integer path '$[0].value'
, bk_version_ref_id integer path '$[1].value'
, bk_scenario varchar2 path '$[2].value'
, bk_cycle varchar2 path '$[3].value'
)
)
) j2
)
select q2.sk_output_value
from q1 join q2 using (bk_ref_id, bk_version_ref_id, bk_scenario, bk_cycle)
;

Dynamic CASE WHEN in Postgresql

I have a list of Conversations, that come from multiple pages as below:
[
{
"id": 1,
"page_id": 1,
"name": "name 1",
"assigned_user_ids": ["user1"]
},
{
"id": 2,
"page_id": 2,
"name": "name 2",
"assigned_user_ids": ["user2"]
},
{
"id": 3,
"page_id": 1,
"name": "name 3",
"assigned_user_ids": ["user2"]
},
{
"id": 4,
"page_id": 2,
"name": "name 4",
"assigned_user_ids": ["user1"]
}
]
Imagine that "User 1" is calling the query, and User 1 can get all items of page_id = 1 (because user 1 is administrator), but in page_id = 2 he/she
only get the items that has been assigned to, in this case is item with id = 4.
So when user 1 query, what I want to received is:
[
{
"id": 1,
"page_id": 1,
"name": "name 1",
"assigned_user_ids": ["user1"]
},
{
"id": 3,
"page_id": 1,
"name": "name 3",
"assigned_user_ids": ["user2"]
},
{
"id": 4,
"page_id": 2,
"name": "name 4",
"assigned_user_ids": ["user1"]
}
]
This is my existing query in SQL look like:
SELECT * FROM Conversations
WHERE PageId IN (1, 2)
Can any one tell me how to modify my SQL to resolve my problem?
Thank you very much!
You can use OR It will either give you what is on page one, so everything from there, or everything that has been assigned to userId 1. So effectively only the things that have been assigned on every other page.
SELECT * FROM Conversations
WHERE PageId = 1 OR userId = 1
If you want to restrict this to only some pages, you can still use IN.
SELECT * FROM Conversations
WHERE PageId = 1 OR userId = 1 AND pageId IN (2,3,4)

SQL JSON : Nest few nodes under a custom node using sql query FOR JSON

So I have written a query that gives the output as an array of JSON objects, one of the objects is below
{
"cardType": "abc",
"createdOnDateTime": "2020-03-26",
"courseName": "course1",
"courseID": 1,
"sectionName": 1,
"studentList": [
{
"name": "student 1",
"nameLink": "0"
},
{
"name": "student 2",
"nameLink": "0"
},
{
"name": "student 3",
"nameLink": "0"
}
]
}
But I want the output as
{
"cardType": "abc",
"createdOnDateTime": "2020-03-26",
"payload" : {
"courseName": "course1",
"courseID": 1,
"sectionName": 1,
"studentList": [
{
"name": "student 1",
"nameLink": "0"
},
{
"name": "student 2",
"nameLink": "0"
},
{
"name": "student 3",
"nameLink": "0"
}
]
}
}
I have used 'For JSON Auto' phrase at the end of my Select query and as the course and student has a One-to-many relation, the student gets formatted in an array. What I want is that few nodes along with the "studentList" node array should be nested under a custom node 'payload'. How can this be achieved in SQL query using the For JSON and it's related properties?
Totally guessing here on what your data and query looks like based on what little you've given us so far. Use a subquery for studentList with for json auto then, on your outer query use for json path, without_array_wrapper.
When using for json path you can nest elements inside each other by giving them dot-separated paths, i.e.: separating parent elements from children with period (.) characters, such as the following...
create table dbo.Course (
cardType nvarchar(3),
createdOnDateTime date,
courseName nvarchar(20),
courseID int,
sectionName int
);
insert dbo.Course values
('abc', '2020-03-26', 'course1', 1, 1);
go
create table dbo.Student (
courseID int,
name nvarchar(20),
nameLink nvarchar(20)
);
insert dbo.Student values
(1, 'student 1', '0'),
(1, 'student 2', '0'),
(1, 'student 3', '0');
go
select
cardType,
createdOnDateTime,
[payload.courseName] = courseName,
[payload.courseID] = courseID,
[payload.sectionName] = sectionName,
[payload.studentList] = (
select name, nameLink
from dbo.Student S1
where S1.courseID = C1.courseID
for json auto
)
from dbo.Course C1
where courseID = 1
for json path, without_array_wrapper;
go
Which yields the result...
{
"cardType": "abc",
"createdOnDateTime": "2020-03-26",
"payload": {
"courseName": "course1",
"courseID": 1,
"sectionName": 1,
"studentList": [
{
"name": "student 1",
"nameLink": "0"
},
{
"name": "student 2",
"nameLink": "0"
},
{
"name": "student 3",
"nameLink": "0"
}
]
}
}
My query was resolved eventually, I found this really helpful video on youtube that exactly shows what I had to do. Click here for the video.
Also one more thing, this video is a very good example, but for large size data, this approach makes the query very slow.