I am trying to fetch data using MyBatis association. The data fetched includes list of person, each of these person have a list of companies associated with them. (see POJO) Currently, there are only two person in DB, say P1 and P0. P1 is associated with Company C1 and C2 and P0 is associated with only C1. (see sql result)
My result map contains a map for person, which itself contains an association of a map for company. (see result map)
When I am fetching the data in sql three rows are coming in the following order: (see sql result)
P1 with C1
P0 with C1
P1 with C2
When I am using "order by person, company" I am getting a correct object, i.e., List of person having two value one for P1 and other for P0, with P1 having list of C1 and C2, and P0 having list of only C1. (see JSON#1)
However, when I am not using "order by" then I am getting incorrect object list having a two objects of P1 (having list of C1 and C2). There is no object of P0. (see JSON#2)
I tried using id (as unique identifier) for company and person result map. I tried nested mapping as well.
Java side:
POJO:
public class Person {
private String personId;
private String firstName;
private String lastName;
private List<CompanyWiseDetails> companyWiseDetails;
// setters and getters
}
public class CompanyWiseDetails {
private String companyId;
private String companyName;
private String payrollCycle;
private Double januaryCatch;
// setters and getters
}
DAO:
final Map<Object, Object> paramMap = new HashMap<Object, Object>();
paramMap.put("universeEndDate", this.getUniverseEndDate());
paramMap.put("projectionDate", projectionDate);
SqlSession.selectList("fetchData")
Result Map:
<resultMap id="person" type="Person">
<id property="personId" column="person_id" />
<result property="firstName" column="first_name" />
<result property="lastName" column="last_name" />
<!-- few other fields which can be null -->
<collection
property="companyWiseDetailsList"
resultMap="companyEntityWiseDetails" />
</resultMap>
<resultMap id="companyEntityWiseDetails"
type="CompanyWiseDetails">
<id property="companyId" column="company_id" />
<result property="companyName" column="company_name" />
<result property="payrollCycle" column="payroll_cycle" />
<!-- few other fields which can be null -->
</resultMap>
SQL:
<select id="fetchData" resultMap="person" >
<include refid="toCreateTemporary_table"/>
select
table_one.person_id as person_id,
company_table.hr_company_code as company_id,
tCompany.PayrollCycle as payroll_cycle
from table_one table_one
join company_table_strategy company_table
on company_table.person_id = table_one.person_id
and company_table.as_on_date = #{projectionDate}
and company_table.tt_end= #{universeEndDate}
join tCompany
on company_table.hr_company_code = tCompany.HRCompanyCode
left join
#temporary_table
on #temporary_table.company_id = company_table.hr_company_code
and #temporary_table.person_id = table_one.person_id
where
table_one.as_on_date = #{projectionDate}
and table_one.tt_end= #{universeEndDate}
order by
person_id, entity_id
drop table #temporary_table
</select>
SQL output
person_id company_id payroll_cycle company_name cash_compensation random_percentage income comp field1 bonus field2
P1 C1 bi_weekly C1_name 5000.00000000 50.00000000 200112.10000000 60.10000000 NULL NULL NULL
P0 C1 bi_weekly C1_name 5000.00000000 50.00000000 100112.10000000 30.10000000 NULL NULL NULL
P1 C2 bi_weekly C2_name 5000.00000000 50.00000000 200112.10000000 30.10000000 362906.82000000 25000.00000000 1000.00000000
Response JSON when order by is used:
[
{
"personId": "P0",
"firstName": null,
"lastName": null,
"companyEntityWiseDetailsList": [
{
"companyId": "C1",
"companyName": null,
"payrollCycle": "bi_weekly"
}
]
},
{
"personId": "P1",
"firstName": null,
"lastName": null,
"companyEntityWiseDetailsList": [
{
"companyId": "C1",
"companyName": null,
"payrollCycle": "bi_weekly",
},
{
"companyId": "C2",
"companyName": null,
"payrollCycle": "bi_weekly",
}
]
}
]
Response JSON when order by is not used:
[
{
"personId": "P1",
"firstName": null,
"lastName": null,
"companyEntityWiseDetailsList": [
{
"companyId": "C1",
"companyName": null,
"payrollCycle": "bi_weekly",
},
{
"companyId": "C2",
"companyName": null,
"payrollCycle": "bi_weekly",
}
]
},
{
"personId": "P1",
"firstName": null,
"lastName": null,
"companyEntityWiseDetailsList": [
{
"companyId": "C1",
"companyName": null,
"payrollCycle": "bi_weekly",
},
{
"companyId": "C2",
"companyName": null,
"payrollCycle": "bi_weekly",
}
]
}
]
Should "order by" have an impact on the result
Related
I have a jsonb object like this:
{
"members": [
[
"1966-07-31",
null,
{
"last_name": "ss",
"first_name": "ss"
}
],
[
"1968-12-17",
"spouse",
{
"last_name": "kk",
"first_name": "kk"
}
]
]
}
I want to convert it to.
{
"applicants": [
{
"last_name": "ss",
"first_name": "ss"
}
{
"last_name": "kk",
"first_name": "kk"
}
]
}
Essentially taking the third element of each member and putting is an object in a new array 'applicant'. I don't need the member data that is outside the object.
I can run a PHP script to loop through all the rows and update it. But I'm wondering if I can write this in plain sql query?
Thanks.
You should use jsonb_array_elements with two CROSS JOIN for extract JSON array data then aggregate them
Dynamic array:
Demo
select
jsonb_build_object('applicants', jsonb_agg(e2.value))
from
test t
cross join jsonb_array_elements(t.obj -> 'members') as e1
cross join jsonb_array_elements(e1.value) as e2
where
e2.value ? 'first_name'
and e2.value ? 'last_name'
Static array:
If your structure is specific you don't need a loop over the array and can use the below query:
Demo
select
jsonb_build_object('applicants', jsonb_agg(e1.value -> 2))
from
test t
cross join jsonb_array_elements(t.obj -> 'members') as e1
For the following data tables and function in pg12
create table orders
(
orderid integer, grandtotal numeric(10, 2)
)
create table odetails
(
orderid integer, detailid integer, description text
)
create function jorder() returns json as
begin
return query select od.orderid, od.grandtotal, ds.detailid, ds.description
from orders od
join odetails ds on od.orderid = ds.orderid;
end;
How do I get return data in a JSON hierarchy like below?
[{
"orderid": 1,
"grandtotal": 100.00,
"details": [{
"detailid": 11,
"description": "pen"
},
{
"detailid": 12,
"description": "orange"
}
]
}, {
"orderid": 2,
"grandtotal": 200.00,
"details": [{
"detailid": 21,
"description": "book"
},
{
"detailid": 22,
"description": "coffee"
},
{
"detailid": 23,
"description": "tea"
}
]
}]
You should look into json functions . You need json_build_object to form the objects and json_agg to aggregate them into json array:
CREATE FUNCTION jorder()
RETURNS json
LANGUAGE sql
AS $$
SELECT
json_agg(orders.order)
FROM (
SELECT
json_build_object(
'orderid', od.orderid,
'grandtotal', od.grandtotal,
'details', array_agg(
json_build_object(
'detailid', ds.detailid,
'description', ds.description
)
)
) as order
FROM
orders od
JOIN odetails ds on od.orderid = ds.orderid
GROUP BY
od.orderid, od.grandtotal
) as orders
$$;
Example at db<>fiddle
I have a JPA entity corresponding to a table in a database in which I have following
#Type(type = "jsonb")
#Column(name = "detail", columnDefinition = "jsonb")
private List<CustomObject> customObjectList;
The detail column in the database is of type JSON, and the entry for the column in the database looks like:
[
{
"field1": "1",
"field2":"2"
},
{
"field1": "3",
"field2": "5"
},
{
"field1": "4",
"field2": "6"
}
]
Where field1 and field2 are attributes of customObject.
But, when I fetch them using a GET API, it gives me a class cast exception
Something like
LinkedHashMap cannot be converted to List<CustomObject>.
Any suggestion how to resolve it?
I have field extra with type jsonb in my table product. And I need get uniq key with uniq values for each key from all products row. Example data in extra field
{"SIZE": "110/116", "COLOUR": "Vit", "GENDER": "female", "AGE_GROUP": "Kids", "ALTERNATIVE_IMAGE": "some_path"}
for now I use query like this
select DISTINCT e.key, array_agg(DISTINCT e.value) as fields
from products AS p
join jsonb_each_text(p.extras) e on true
GROUP BY e.key
Ad have respnse (small part with some keys in full response all keys are present) like this
[
{
"key": "AGE_GROUP",
"fields": "{Adult,children,Kids}"
},
{
"key": "GENDER",
"fields": "{female,male,man}"
}
]
how to change it to array for fields alias ?
like this
[
{
"AGE_GROUP": ["Adult","children","Kids"]
},
{
"GENDER": ["female","male","man"]
}
]
or maybe whould be great like this
[
"some_alias": [{"AGE_GROUP": "Adult", "AGE_GROUP": "children", "AGE_GROUP": "Kids"}],
"some_alias": [{"GENDER": "female", "GENDER": "male", "GENDER": "man"}]
]
This will get you the former form I think:
select jsonb_agg(jsonb_build_object(k,v)) from (
select DISTINCT e.key, jsonb_agg(DISTINCT e.value) as fields
from products AS p
join jsonb_each_text(p.extras) e on true
GROUP BY e.key
) b(k,v);
Best regards,
Bjarni
CREATE TABLE company (id SERIAL, companyJson JSONB);
CREATE INDEX comapny_gin_idx ON company USING gin (companyJson);
INSERT INTO company (id, companyJson)
VALUES (1, '[{"name": "t", "company": "company1"}]');
INSERT INTO company (id, companyJson)
VALUES (2, '[{"name": "b", "company":"company2"}, {"name": "b", "company":"company3"}]');
SELECT * FROM company WHERE companyJson #> '[{"company": "company2" , "name": "b"}]';
The output of the above program is
2 [{"name": "b", "company": "company2"}, {"name": "b", "company": "company3"}]
Is there anyway to return {"name": "b", "company": "company2"} instead whole row.
I can only think of unnesting the array and the return the element from that:
SELECT x.j
FROM company c
cross join jsonb_array_elements(c.companyjson) as x(j)
where x.j = '{"company": "company2" , "name": "b"}'
You can directly return the first component through companyJson -> 0 which contains -> operand returning the first component by argument zero :
SELECT companyJson -> 0 as companyJson
FROM company
WHERE companyJson #> '[{"company": "company2" , "name": "b"}]';
Demo