SQL / Hibernate Criteria - Group By Trouble - java

I'm having some trouble here to create an appropriate SQL query. Any help will be much appreciated!
Some background:
I have the following entities
Equipment
id
nickname
owner_indicator
{...}
EquipmentGroup_Equipment
equipment_id
equipment_group_id
EquipmentGroup
id
name
description
I need to do a SQL / JPA Hibernate query that returns me:
EquipmentGroup.name, EquipmentGroup.description, Equipment.owner_indicator
And this will be grouped by EquipmentGroup.id, so if I have 10 equipments inside the group it will return information grouped by the EquipmentGroup.
The thing is, when I have for example more than one owner_indicator inside a EquipmentGroup it will return 2 rows. This is SQL 101. But i must return only one line with a blank text instead of the Owner Indicator.
What is the easiest way to do this ? I'd be glad to have the answer in SQL, but much more than glad to have it in Criteria JPA, heh.
If it does matter, I'm using Oracle 12c.
Thanks!
EDIT
As requested, here is some data:
Equipment
id nickname owner_indicator
1 EQP01 'V'
2 EQP02 'T'
EquipmentGroup_Equipment
equipment_group_id equipment_id
1 1
1 2
EquipmentGroup
id name description
1 GRP1 Group 1
My wanted resultSet is:
Result
EquipmentGroup.name EquipmentGroup.description, Equipment.owner_indicator
GRP1 Group 1 (empty string)
That empty string would be returned because I don't want 2 rows, like
Result
EquipmentGroup.name EquipmentGroup.description, Equipment.owner_indicator
GRP1 Group 1 'T'
GRP1 Group 1 'V'
If anything more than that is needed please advise.
Thanks!

I thin k you must to use a main query on EquipmentGroup and a subquery about return data on Equipment.
If you have more than 1 equipment rows about one group you must return DISTINCT empty; if you have 1 row returns owner_indicator otherwise you can return 'None'
Try this:
SELECT DISTINCT eg.name, eg.description,
(SELECT
CASE
WHEN count(e.id) > 1 THEN DISTINCT 'EMPTY'
WHEN count(e.id) = 1 THEN e.owner_indicator
ELSE 'none'
END
FROM Equipment e
WHERE e.equipmentGroup.id = eg.id)
FROM EquipmentGroup eg

Related

Simple SQL query on highest ID

I unsuccessfully attempted to leverage Java's DerivedQueries but cannot accomplish the required result so I have to manually write a SELECT Statement.
I want to display one single record in my UI. This should be the most recently generated record (which means it has the highest ID Number) associated with a category that we call "ASMS". In other words, look through all the rows that have ASMS#123, find the one that has the highest ID and then return the contents of one column cell.
ASMS: Entries are classified by 11 specific ASMS numbers.
ID: AutoGenerated
PPRECORD: New entries being inserted each day
I hope the image makes more sense.
//RETURN ONLY THE LATEST RECORD
//https://besterdev-api.apps.pcfepg3mi.gm.com/api/v1/pprecords/latest/{asmsnumber}
#RequestMapping("/pprecords/latest/{asmsNumber}")
public List<Optional<PriorityProgressEntity>> getLatestRecord(#PathVariable(value = "asmsNumber") String asmsNumber) {
List<Optional<PriorityProgressEntity>> asms_number = priorityprogressrepo.findFirst1ByAsmsNumber(asmsNumber);
return asms_number;}
The ReactJS FE makes an AXIOS.get and I can retrieve all the records associated with the ASMS, but I do not have the skill to display only JSON object that has the highest ID value. I'm happy to do this in the FE also.
I tried Derived Queries. .findFirst1ByAsmsNumber(asmsNumber) does not consider the highest ID number.
Try this:
SELECT pprecord FROM YourTable WHERE id =
(SELECT MAX(id) FROM YourTable WHERE asms = '188660')
Explanation:
First line select pprecord, second line select the id
I'll improve the answer if any additional question. Upvotes and acceptions are appreciated~

How to make a query with the operator MIN() and something filtered inside in JPQL?

I have a class Sponsor who has a Collection<Campaign>. And each Campaign has just one Sponsor.
For example, if I have it:
SELECT MIN(s.campaigns.size) FROM Sponsor s;
It returns the campaigns.size of the Sponsor who has the minimum campaigns.
But if I want to COUNT the campaigns 'c' whose c.attribute=null per Sponsor, and then return the minimum of it?
A visual example of what I want to get could be:
select min(select count(c) from Campaign c where c.sponsor.id=s.id and c.finishMoment is null) from Sponsor s;
The thing is that it's not possible to include a SELECT into the function MIN.
Hard to say what your looking for. Here's something along those lines.
** Sorry, not a jpql guy, but apparently you can take the first result, so you could do the select and order it by the count and just take the first result
Sorry, your going to have to work out the join, but you get the idea.
SELECT Campaign.id,COUNT(Campaign.id)
FROM Campaign
JOIN Sponsor on (Sponsor.id = Campaign.id)
WHERE finishMoment is null
GROUP BY Campaign.id
ORDER BY COUNT(Campaign.id)
**This is SQL
SELECT MIN(sponsorCount)
FROM (SELECT Campaign.id,COUNT(*) sponsorCount
FROM Campaign
JOIN Sponsor on (Sponsor.id = Campaign.id)
WHERE finishMoment is null
GROUP BY Campaign.id);

ORMLite groupByRaw and groupBy issue on android SQLite db

I have a SQLite table content with following columns:
-----------------------------------------------
|id|book_name|chapter_nr|verse_nr|word_nr|word|
-----------------------------------------------
the sql query
select count(*) from content where book_name = 'John'
group by book_name, chapter_nr
in DB Browser returns 21 rows (which is the count of chapters)
the equivalent with ORMLite android:
long count = getHelper().getWordDao().queryBuilder()
.groupByRaw("book_name, chapter_nr")
.where()
.eq("book_name", book_name)
.countOf();
returns 828 rows (which is the count of verse numbers)
as far as I know the above code is translated to:
select count(*) from content
where book_name = 'John'
group by book_name, chapter_nr
result of this in DB Browser:
| count(*)
------------
1 | 828
2 | 430
3 | 653
...
21| 542
---------
21 Rows returned from: select count(*)...
so it seems to me that ORMLite returns the first row of the query as the result of countOf().
I've searched stackoverflow and google a lot. I found this question (and more interestingly the answer)
You can also count the number of rows in a custom query by calling the > countOf() method on the Where or QueryBuilder object.
// count the number of lines in this custom query
int numRows = dao.queryBuilder().where().eq("name", "Joe Smith").countOf();
this is (correct me if I'm wrong) exactly what I'm doing, but somehow I just get the wrong number of rows.
So... either I'm doing something wrong here or countOf() is not working the way it is supposed to.
Note: It's the same with groupBy instead of groupByRaw (according to ORMLite documentation joining groupBy's should work)
...
.groupBy("book_name")
.groupBy("chapter_nr")
.where(...)
.countOf()
EDIT: getWordDao returns from class Word:
#DatabaseTable(tableName = "content")
public class Word { ... }
returns 828 rows (which is the count of verse numbers)
This seems to be a limitation of the QueryBuilder.countOf() mechanism. It is expecting a single value and does not understand the addition of GROUP BY to the count query. You can tell that it doesn't because that method returns a single long.
If you want to extract the counts for each of the groups it looks like you will need to do a raw query check out the docs.

Modifying the contents of a result returned by a Oracle Sql query

One of our clients have requested information about customers.
I have written the query below, to extract the list of customers.
select * from customer;
Id | Name | Status
----+----------+-----------
1 Azam 0
2 Kapil 1
3 Osama 2
But the issue is the "Status" column, which is an enum from the java code(We have used hibernate for ORM).
Therefore, it is stored in the database as digits. The problem is, I have to replace the digits in the "Status"
column with constants before sending it to the customer, since the customer does not understand digits. I do this
by generating an excel file of the result set and amending the Status column values.
E.x.
In the Status column:
0 means Prospect, 1 means Active and 2 means Existing.
Question:
Is there a way to modify the result set returned from a query to obtain the following from Oracle alone:
select * from customer;
Id | Name | Status
----+----------+------------
1 Azam Prospect
2 Kapil Active
3 Osama Existing
I think you can use the decode function in the following way:
select id,name,decode(status,0,'Prospect',1,'Active',2,'Existing) from customer;
Regards
Giova
If you have a table containing the status details, then it should just be a matter of joining to that table and outputting the status description.
If you don't, and you know the status numbers/description won't change, then you could use a case statement:
select id, name, case when status = 0 then 'Prospect'
when status = 1 then 'Active'
when status = 2 then 'Existing'
...
else null -- can be omitted if null is the desired default, or change the null to the output required
end status
from customer;
In addition to other answers, if you want to store string values of Enum constants in the database, use this mapping
#Enumerated(value=EnumType.STRING)
private MyEnum myEnum;

How to select the field value if field in all child records are the same

I don't know if I'm wording this question correctly, but here it goes.
This is a web application using java, oracle, hibernate.
I have 2 tables in a one (items) to many (tasks) relationship.
Items
item_id name
active_status
etc
Tasks
task_id
item_id
active_status
progress_status
etc
The item's status is made up of the statuses of all of its tasks. Here's the logic...
If Item Status is Canceled or On Hold...return Item Active Status
If there are no tasks, return Completed
If All Tasks are Active and NOT Superseded, then
...return Not Started if all tasks are Not Started
...return Completed if all tasks are Completed
...return On Hold if all tasks are On Hold
Otherwise return Started
I want to do this using SQL and map it to a field in my hibernate mapping file.
I've tried many things over the past several days, and can't seem to get it to work. I tried grouping the records and if 1 record was found, return that status. I've used decode, case, etc.
Here are a few examples of things I've tried. In the second example I get a 'not a single group group function' error.
Any thoughts?
select decode(i.active_status_id, 'OH', i.active_status_id, 'Ca', i.active_status_id,t.progress_status_id)
from tasks t
LEFT OUTER JOIN Items i
ON i.item_id = t.item_id
where t.item_id = 10927815 and t.active_status_id = 'Ac' and t.active_status_id != 'Su'
group by i.active_status_id, t.progress_status_id;
select case
when (count(*) = 1) then progress_status_id
else 'St'
end
from
(select progress_status_id
from tasks t
where t.item_id = 10927815 and (t.active_status_id = 'Ac' and t.active_status_id != 'Su') group by t.progress_status_id)
perhaps somthing like this
SELECT
item_id
, CASE
WHEN active_status IN ('Canceled', 'On Hold') THEN active_status
WHEN t_num = 0 THEN 'Completed'
WHEN flag_all_active = 1 AND flag_all_not_started = 1 THEN 'Not Started'
WHEN flag_all_active = 1 AND flag_all_completed = 1 THEN 'Completed'
WHEN flag_all_active = 1 AND flag_all_on_hold = 1 THEN 'On Hold'
ELSE 'Started'
END
FROM
(
SELECT
i.item_id
, i.active_status
, sum(CASE WHEN t.task_id is NULL THEN 0 ELSE 1 end ) as t_num
, MIN( CASE t.active_status WHEN 'Ac' THEN 1 ELSE 0 END ) as flag_all_active
, MIN( CASE t.progress_status_id WHEN 'Not Starten' THEN 1 ELSE 0 END ) as flag_all_not_started
, MIN( CASE t.progress_status_id WHEN 'Completed' THEN 1 ELSE 0 END ) as flag_all_completed
, MIN( CASE t.progress_status_id WHEN 'On Hold' THEN 1 ELSE 0 END ) as flag_all_on_hold
FROM
items i
left outer join tasks t on (t.item_id = i.item_id )
group by i.item_id
)
;
If you're using annotations you can use #Formula("sql query here") for your derived properties.
See Hibernate formula docs for a (surprisingly brief) explanation.
Alternatively, since you're dealing with relatively large lists of items, it would be better to make the status calculations part of your initial query thus avoiding the database getting hammered by hundreds or thousands of requests. This is what will probably happen if you iterate over each item in the list.
I would recommend joining the status calculation to whatever query you are using to generate your list (presumably in a NamedQuery). This lets your database do all the heavy lifting without being slowed down by the network, which is what it is best at. The Hibernate docs give lots of helpful examples of queries you can try.

Categories

Resources