Oracle JSON query - sql

I have a JSON column which on persons table which stores the best activities people have done in countries they visited like this...
{
"countries": [
{
"name": "Ireland",
"bestActivity": {
"name": "Drinking"
}
},
{
"name": "Scotland",
"bestActivity": {
"name": "Dancing"
}
}
]
}
Someone else might be:
{
"countries": [
{
"name": "Ireland",
"bestActivity": {
"name": "Football"
}
},
{
"name": "England",
"bestActivity": {
"name": "Golf"
}
}
]
}
I want to select all the people who visited Ireland and with best activity of Drinking in Ireland and also visited Scotland and with the best activity of Drinking.
Really struggling. Any tips?

You can use the JSON_EXISTS function to filter your table based on the criteria you described. I have built a sample query below using the JSON structures you provided in your question.
WITH
sample_table (first_name, json_col)
AS
(SELECT 'John', '{
"countries": [
{
"name": "Ireland",
"bestActivity" : {
"name": "Drinking"
},
},
{
"name": "Scotland",
"bestActivity" : {
"name": "Dancing"
}
}
}' FROM DUAL
UNION ALL
SELECT 'Jane', '{
"countries": [
{
"name": "Ireland",
"bestActivity" : {
"name": "Football"
},
},
{
"name": "England",
"bestActivity" : {
"name": "Golf"
}
}
}' FROM DUAL)
SELECT *
FROM sample_table s
WHERE JSON_EXISTS (s.json_col, '$.countries[*]?(#.name == "Scotland")')
AND JSON_EXISTS (
s.json_col,
'$.countries[*]?(#.name == "Ireland" && #.bestActivity.name == "Drinking")');

You can use JSON_TABLE() function as your database version is 12c(for all subversions) such as
SELECT first_name
FROM t,
JSON_TABLE(jscol, '$.countries[*]'
COLUMNS (
country VARCHAR2(90) PATH '$.name',
bestActivity VARCHAR2(90) PATH '$.bestActivity.name'
)
)
WHERE (country = 'Ireland' AND bestActivity = 'Drinking')
OR country = 'Scotland'
GROUP BY first_name
HAVING COUNT(*)>1
Demo
You can use JSON_EXISTS() function is database version is 12cR2+ in such a format
SELECT first_name
FROM t
WHERE JSON_EXISTS(jscol,
'$.countries?(#.name == "Ireland"
&& #.bestActivity.name == "Drinking")')
AND JSON_EXISTS(jscol,
'$.countries?(#.name == "Scotland")');
Demo
Notice that the query should be invoked after issuing SET DEFINE OFF when SQL*Plus is used in order to prevent the && operands to be interpreted as a substitution variable.

Related

How to query in Array with Typeorm's Repository

This is the current repository code.
After joining the student and director tables in the attendance table, join the location table again in the student table, and join the schedule table in the director table to get the location information and date.
return await this.createQueryBuilder('tbl_attendance')
.leftJoin('tbl_attendance.student', 'student')
.leftJoin('student.location', 'location')
.select([
'student.gcn',
'student.id',
'student.name',
'tbl_attendance.period',
'location.name',
'tbl_attendance.state',
])
.leftJoin('tbl_attendance.director', 'director')
.leftJoin('director.schedule', 'schedule')
.where('location.floor= :floor', { floor: floor })
.andWhere('schedule.date= :date', { date: date })
.andWhere('tbl_attendance.state= :state', { state: state })
.getMany();
}
And this is the currently returned json
[
{
"state": "MOVE",
"period": 7,
"student": {
"id": 1,
"name": "anne",
"gcn": "1301",
"location": {
"name": "semina 2-1"
}
}
},
{
"state": "MOVE",
"period": 8,
"student": {
"id": 1,
"name": "anne",
"gcn": "1301",
"location": {
"name": "semina 2-1"
}
}
}
]
I wish it was returned like this.
[
{
"gcn": 1301,
"student_id": 3,
"student_name": "anne",
"student_attendance": [
{
"period" : 8
"location_name": null || "semina2-1",
"state": "MOVE"
},
{
"period": 9
"location_name": null || "semina2-1",
"state": "MOVE"
},
{
"period": 10
"location_name": null || "semina2-1",
"state":"MOVE"
}
]
}
]
How do I get the student's place id and status for each class separately as an array?
Perhaps you should query the student table and join the related entities onto that one. That way, your result would be an array of students, with each its own array of attendance object.
Now, when it comes to joining with TypeORM, joined tables will always be nested in the resulting object, as an array or an object for one-to-many and many-to-one relationships respectively. There is no straightforward way to control the shape of the resulting data other than mapping it manually.

How to access json array elements (keys) , values in json nested dictionary type using postgresql?

I have a nested structure json .
How to extract the specific elements(keys) and values?
How to access " sky: selling":"1"
Or "U1":"0000" ?
I tried json_object_keys and json_array_elements for extracting the array .
But I don't know exactly how to do this query.
Example code:
Table- record and column name : report
{
"PIname": {
"n1": "x1",
"n2": "x2",
"params": {
"S1": {
"code1": "y1",
"Code2": "y2",
},
"id": "2d",
"Dest": {
"Code3": "mi"
}
},
"PIDataArea": {
"m1": null,
"PInven": {
"head": {
"Code4": "Increase",
"line": "2020-01"
},
"PILine": [
{
"u1": "0000",
"u2": "0",
"u3": "1",
"modes": {
"#cID": "Sng",
"#txt": "12.21"
} },
{
"Qualify": ".0001",
"QOrder": "1",
"UPriceAmt": {
"#cID": "sng",
"#txt": "13" },
"sky:Qa": ".000",
"sky:Partcode": {
"#c1ID": "a"
},
"sky:SCode": "Ni",
"sky:PItem": {
"sky:ID": "h"
},
"sky:Forest": {
"sky:q1": [
{
"sky:selling": "1"
}
{
"sky:selling": "0"
}
]
} } }} }}
I tried lot ,one example query here like,
Select * from record r
Where exists( select report->'sky: selling' from json_each(r.report) b where b.value->>'sky:selling' Ilike '0');
You can use the json_path_query or jsonb_path_query function. Example to extract the element with key = "sky:selling" :
json_path_query(r.report, $.** ? (#.key == 'sky:selling'))

How to update multiple occurrence a specific value of a object present in array of object within Postgres JSON Field

Here is my JSON field where has multiple users with the same name. I want to update all users whose name is Devang to Dev
JSON
{
"user": [
{
"user_name": "Devang",
"user_weight": 0.7676846955248864
},
{
"user_name": "Meet",
"user_weight": 0.07447325861051013
},
{
"user_name": "Devang",
"user_weight": 0.056163873153859706
}
],
"address": [
{
"address_name": "India"
}
]
}
After Update The JSON would be
{
"user": [
{
"user_name": "Dev",
"user_weight": 0.7676846955248864
},
{
"user_name": "Meet",
"user_weight": 0.07447325861051013
},
{
"user_name": "Dev",
"user_weight": 0.056163873153859706
}
],
"address": [
{
"address_name": "India"
}
]
}
Here I have tried this query but update only the first occurrence due to subquery.
with cte as (
select id, ('{user,'||index-1||',user_name}')::text[] as json_path
from user_table, jsonb_array_elements(json_field->'user')
with ordinality arr(vals,index) where arr.vals->>'user_name' ='Devang'
)
update user_table
set json_field = jsonb_set(json_field,cte.json_path,'"Dev"',false)
from cte where user_table.id=cte.id;
Please also look at this DEMO
Any answer will be appreciated
You may use string function REPLACE:
UPDATE user_table
SET json_field = REPLACE(json_field :: TEXT, '"user_name": "Devang"', '"user_name": "Dev"') :: JSONB;
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=fa36275977f85a1233bcbec150ada266

How to realize sum(field) group by multi field in elasticsearch?

I'm using logstash to save row data from MySQL to ElasticSearch. How to calculate sum on one field group by two fields?
For example, here is one table named "Students", it has several columns: id, class_id, name, gender, age;
and here is one SQL query:
select class_id, gender, sum(age) from Students group by class_id, gender;
How to translate this SQL to ElasticSearch high level rest client API call?
Below is my try, but it is not correct:
public TermsAggregationBuilder constructAggregation() {
TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_classid")
.field("classId.keyword");
aggregation = aggregation.subAggregation(AggregationBuilders.terms("by_gender").field("gender.keyword"));
aggregation = aggregation.subAggregation(AggregationBuilders.sum("sum_age")
.field("age"));
return aggregation;
}
Following is the raw query for your sql statement
POST aggregation_index_2/_search
{
"size": 0,
"aggs": {
"gender_agg": {
"terms": {
"field": "gender"
},
"aggs": {
"class_id_aggregator": {
"terms": {
"aggs": {
"field": "class_id"
},
"age_sum_aggregator": {
"sum": {
"field": "age"
}
}
}
}
}
}
}
}
Mappings
PUT aggregation_index_2
{
"mappings": {
"properties": {
"gender": {
"type": "keyword"
},
"age": {
"type": "integer"
},
"class_id": {
"type": "integer"
}
}
}
}

Unwind an array in DocumentDB query

I have documents that look like this:
[
{
"id": "e1bb9b05-11f2-459e-37d3-9bf9fed56c96",
"name": "bulbasaur",
"type": [
{
"slot": 2,
"type": {
"url": "https://pokeapi.co/api/v2/type/4/",
"name": "poison"
}
},
{
"slot": 1,
"type": {
"url": "https://pokeapi.co/api/v2/type/12/",
"name": "grass"
}
}
]
}
]
The following query is about as close as I can get, but not quite the output I'm hoping for.
Query
SELECT
c.id, c.name, t.type.name as type
FROM
c
JOIN
t IN c.types
WHERE
c.name = "bulbasaur"
Result
[
{
"id": "e1bb9b05-11f2-459e-37d3-9bf9fed56c96",
"name": "bulbasaur",
"type": "poison"
},
{
"id": "e1bb9b05-11f2-459e-37d3-9bf9fed56c96",
"name": "bulbasaur",
"type": "grass"
}
]
Hoping for
[
{
"id": "e1bb9b05-11f2-459e-37d3-9bf9fed56c96",
"name": "bulbasaur",
"types": ["poison", "grass"]
}
]
Is this possible with a DocumentDB query?
This requires use of DocumentDB UDFs, which can extend query functionality with custom transformations. For example, register this:
function unwindTypeArray(value) {
var result = { id: value.id, name: value.name, types: []};
for (var idx in value.type) {
console.log(idx);
var name = value.type[idx].type.name;
result.types.push(name);
}
return result;
}
Then call it inside a query like:
SELECT udf.unwindTypeArray(c) FROM c WHERE c.name = "bulbasaur"