Query ManyToMany SpringBoot - spring

I have the following modeling:
table hackathon
idEvent int pk ai
...
table team
idTeam int pk ai
...
table hackathon_has_team
hackathon_id int
team_id int
....
And I need to select all the teams that are in an event by event id and I'm breaking my head with it, can anyone help?
I'm trying to do this but it does not work:
#Query("SELECT t "
+ "FROM Team t INNER JOIN hackathon_has_team "
+ "ON hackathon_has_team.team_id = t.id "
+ "WHERE hackathon_has_team.hackathon_id = :hackathon_id")
public Page<Team> getListAllTeamsByIdOfHackathon(#Param("hackathon_id ") Long id, Pageable pageable);

You might need to provide more to get more, but depending on how you are obtaining the list of the teams, you could try:
select * from event_has_team
where (select team_id from table team)
This selects everything from the event_has_team table where the team_id is in the team table. you can also add a where clause for teams you've identified in that sub-select or nit he main select, depending on what you really need.

Related

Sum a List of averages in spring boot jpa query

I have this query thats return a list of averages
#Query("SELECT AVG(p.quantity) FROM Position p GROUP BY p.client.id") public List<Float> findAVGPositions();
But I want to return SUM of averages like this, but it doesn't work
#Query("SELECT SUM(averages) FROM (SELECT AVG(p.quantity) as averages FROM Position p GROUP BY p.client.id)") public Float findSumAVGPositions();
Can you help me? thanks
Unfortunately, in JPQL, nested selects are not permitted in FROM clause. They are allowed only in SELECT and WHERE.
You have two approaches available.
(1) Use findAVGPositions and calculate sum in Java
findAVGPositions().stream().reduce(0f, Float::sum);
(2) Use a native SQL query
#Query(value = "SELECT SUM(averages) " +
"FROM (SELECT AVG(p.quantity) AS averages " +
"FROM position p " +
"GROUP BY client_id) AS averages_select",
nativeQuery = true)
public Float findSumAVGPositions();
Depending on the database you use, AS averages_select alias might be needed or not (PostgreSQL requires it, even if it's not used).
Please, pay attention to use the correct names of a database table for Position entity and a database column for a foreign key client.id.
In my example, I assumed a standard mapping convention: position as a table name, and client_id as a foreign key column.

Spring MVC, Select Special Columns in Native SELECT Query

this is my native SELECT Query in Repository
#Modifying
#Query(value = "SELECT * FROM tasks WHERE title LIKE '%Java%' ORDER BY id DESC ", nativeQuery = true)
List<Task> listAllTasks();
this works ok, but when I use custom column name instead of *, like this
#Modifying
#Query(value = "SELECT title FROM tasks WHERE title LIKE '%Java%' ORDER BY id DESC ", nativeQuery = true)
List<Task> listAllTasks();
I have this error :
org.postgresql.util.PSQLException: The column name id was not found in this ResultSet.
any Help?
The resultset doesn't have the "id" in it, you have to provide it.
You should change the way you are declaring your SQL:
SELECT t.title, t.id FROM tasks t WHERE t.title LIKE '%Java%' ORDER BY t.id DESC
Check out this sort example:Native Queries
Select * from Entity -> returns a List of Entity
Example:
#Query(select * from tasks)
List<Task> findAllTasks();
Select column from Entity -> returns a List of Types of the entity.
Example:
#Query(select t.title from tasks t)
List<String> findTitle_AllTasks();
title is of the type String
Select multiple columns from Entity -> returns an Object[] holding the data
Example:
#Query(select t.id, t.title from tasks t)
List<Object[]> findIdTitle_AllTasks();
So, you are retrieving String type data - title and asking to return a List of Task type. This is causing the problem. You can actually check the hibernate docs under HQL and JPQL to understand this.
Plus, you are doing a SELECT (DQL operation). #Modifying is rudimentary here as it is used for DML operations using Data JPA - UPDATE/DELETE.

Spring Boot #Formula displaying same likeCount on every result

I'm having a problem with my #Formula field. I have three tables: user_acc, song and user_likes_song. I'm trying to display likeCount on songs based on how many times the songs ID appears in the many-to-many table.
My #Formula field in the Song entity looks like this:
#Formula("(SELECT COUNT(s.id) FROM user_acc u INNER JOIN user_likes_song us on u.id = us.user_id " +
"INNER JOIN song s on us.song_id = s.id WHERE us.song_id = s.id )")
private Long likeCount;
Currently when I like a song for the first time it shows "likeCount: 1" on every result. After I like another song it returns "likeCount: 2" on every result and so on.
Seems to me like it's counting all the likes in total, not for the specific song. How can I make it so it so it shows how many times a specific song ID appears in the many-to-many table?
You do the match with every song rows :
INNER JOIN song s on us.song_id = s.id WHERE us.song_id = s.id
What you want is restricting it to the current song entity instance.
In fact, if the #Formula annotation is specified on a field of the Song entity, you don't want to specify Song in the query, instead you want to directly refer the field of the current entity (here id), that is :
WHERE us.song_id = id
So this should do the job :
#Formula("(SELECT COUNT(*) FROM user_acc u INNER JOIN user_likes_song us on u.id = us.user_id " + "WHERE us.song_id = id )")
And I think that you could also simplify more in this way :
#Formula(" (SELECT COUNT(*) FROM user_likes_song us WHERE us.song_id = id) ")
because the join with user account doesn't matter.

Why is "group by" giving only one column as output?

I have a table something like this:
ID|Value
01|1
02|4
03|12
01|5
02|14
03|22
01|9
02|32
02|62
01|13
03|92
I want to know how much progress have each id made (from initial or minimal value)
so in sybase I can type:
select ID, (value-min(value)) from table group by id;
ID|Value
01|0
01|4
01|8
01|12
02|0
02|10
02|28
02|58
03|0
03|10
03|80
But monetdb does not support this (I am not sure may be cz it uses SQL'99).
Group by only gives one column or may be average of other values but not the desired result.
Are there any alternative to group by in monetdb?
You can achieve this with a self join. The idea is that you build a subselect that gives you the minimum value for each id, and then join that to the original table by id.
SELECT a.id, a.value-b.min_value
FROM "table" a INNER JOIN
(SELECT id, MIN(value) AS min_value FROM "table" GROUP BY id) AS b
ON a.id = b.id;

Linq MAX in Where clause in Joined table query

i'm in a situation my mind is blocked en hope someone can help me.
I have two tables. One table with customers of a subsription service and one invoice table.
these tables are not linked with keys in the database for keeping history of invoices if customers are deleted. This way I have to query the customers table joining the invoiceheader table by another unique contraint (not know by the database). This constraint is using name and address together.
An invoice is send one time a year. In the invoice-header table the date is stored when the invoice is created. In a couple of years constomers can have multiple invoices.
i'm trying to create a linq query but i'm looking the wrong way for a solution I'm afraid.
who can point me the right way?
for now i have a query :
var temp = from c in context.customer
from i in context.invoiceheader
where c.name + c.address == i.name + i.address
&& i.invoicedate < DateTime.Now.Year
select c;
With this query I get all customers who have receive an invoice last year and stil have subscribed. The trouble is with new customers who never received an invoice.
What to do for customers where in this case they haven't any invoice records.?
summurized: I want to query the last know invoice. If this invoice is older than a year (previous year)or no invoice is sent at al, i wanna retreive a list of customers the should be sent a new invoice.
I guess that what you want is a left outer join - this way you should be able to get all the customers you need:
var customers = from c in context.customer
join i in context.invoiceheader
on c.Name + c.Address equals i.Name + i.Address
into g
from row in g.DefaultIfEmpty()
where row == null ||row.invoicedate < DateTime.Now.Year
select c;

Resources