Check if any value in list satisfies a condition - java

Suppose I have the following table called Seasons:
...
start_month
end_month
...
2
6
...
3
4
...
...
...
I need to write a query which, for a given list of months, returns all the Seasons that satisfy the condition where at least 1 month in the list is: start_month <= month <= end_month.
I've written this query as a native query with JDBC, except the where clause.
#Repository
public class SeasonsRepositoryImpl implements SeasonsRepositoryCustom {
#PersistenceContext
private EntityManager em;
#Override
public List<SeasonsProjection> findByMonths(List<Integer> months) {
String query = "select * " +
"from seasons as s" +
"where ...."
try {
return em.createNativeQuery(query)
.setParameter("months", months)
.unwrap(org.hibernate.query.NativeQuery.class)
.setResultTransformer(Transformers.aliasToBean(SeasonsProjection.class))
.getResultList();
} catch (Exception e) {
log.error("Exception with an exception message: {}", e.getMessage());
throw e;
}
}
}
I have no idea how to write this, I thought of using the ANY operator until I found out that ANY only works with tables and not lists, I thought of writing this as a subquery with converting the list to a table, but I don't know if that's possible, I couldn't find anything in the MySQL documentation.

In your where clause, you will want to have an OR conditions for each month.
You can generate it in a loop and then concat or something similar.
Your final query for input of 1,3,4,7 for example will look as follows:
SELECT *
FROM seasons as s
WHERE (1 between start_month and end_month
OR 3 between start_month and end_month
OR 4 between start_month and end_month
OR 7 between start_month and end_month)

One way to accomplish this is:
select s.*
from (select 1 as mn union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8
union select 9 union select 10 union select 11 union select 12) as a
inner join season s on a.mn between s.start_month and s.end_month
where a.mn in (:flexibleTypeMonths);

Related

SQL: Get a limit of records per entity

I have the following setup (Java/Hibernate/PostgreSQL):
TeamName {
id: Long;
name: String;
team: Team;
....
}
Series {
id: Long;
season: Season;
dateScheduled: Date;
}
SeriesTeam {
id: Long;
series: Series;
team: TeamName;
}
SeriesTeam {
id: Long;
team: TeamName;
}
What I want to do is do a select of the past n series (say 10) or the next series from the current date. Here's what I have so far:
select s.* from series s
inner join series_teams st on st.series_id = s.id
inner join team_names tn on tn.id = st.team_name_id
where tn.id in (:teamIds) and s.date_scheduled < CURRENT_DATE
order by s.date_scheduled desc
But that is going to get me all the prior series for all teams and I will have to use Java to pick out what I want How would I go about doing what I want? Thanks!
EDIT: For example, say I wanted a limit of 10 per team name, and there are 24 teams, I would want max of 240 records returned to me. (assuming 10 exist before current date)
EDIT2: Here is the code that I want for a single team:
select s. from series s
inner join series_teams st on st.series_id = s.id
where st.team_name_id=85 and s.date_scheduled < CURRENT_DATE
order by s.date_scheduled desc
limit 10
I just need to be able to apply this for all the teams....I don't want to make x SQL calls for every team.
I think this will work. The syntax is in mysql and you can try it at that site the structure they have is similar to yours. you can adjust the limit value to change how many from each employee to return sorted by date. Probably add the current date check there too i guess.
Basically I joined all the needed tables together then created a new column that will tell me if that row is one we should return then added that check in the where clause.
https://www.w3schools.com/sql/trysql.asp?filename=trysql_op_in
SELECT e.employeeid, lastname,orderdate, orderdate in (select orderdate from
orders ord where e.employeeid=ord.employeeid order by orderdate limit 2) as
good FROM Employees as e join orders as o on e.employeeid=o.employeeid where
good=1 order by e.employeeid, o.orderdate;
for your case:
select s.id, s.season_id, s.date_scheduled, st.team_name_id,
s.date_scheduled in (
select s2.date_scheduled from series s2
inner join series_teams st2 on st2.series_id = s2.id
inner join team_names tn2 on tn2.id = st2.team_name_id
where tn.id =tn2.id and s2.date_scheduled < CURRENT_DATE
order by s.date_scheduled desc limit 5
) as foo
from series s
inner join series_teams st on st.series_id = s.id
inner join team_names tn on tn.id = st.team_name_id
where tn.id in (:teamIds) and foo = true
order by st.team_name_id, s.date_scheduled desc

How implement friends Relationship android

I'm trying to implement some code for get friends list.
First:
- I have my String id. E.G: 784717
- I have an string with 100 numbers. E.G: 7781,5913,551949194,4919491,...,444131 (One string separated by ,)
- I have 3000 records in my Database with different numbers. (With numbers I mean some kind of ID)
- Of my 100 numbers only 8 are registered in my database.
Question:
How can I know what numbers are registered in the database and insert in other table the relationship?
My table Relationship have this columns:
*number1 - (Here should be my ID)
*number2 - (1 of the 100 numbers that exists)
So in my table Relationship should be 8 new rows.
I tried with :
EXEC('SELECT * FROM Accounts WHERE ID IN(' +#in_mystring+')')
but i don't know how insert in the other table or if is efficiently
Assuming this is SQL Server, and with the help of a parser function
For example
Select * from [dbo].[udf-Str-Parse]('7781,5913,551949194,4919491,...,444131',',')
Returns
Key_PS Key_Value
1 7781
2 5913
3 551949194
4 4919491
5 ...
6 444131
From this sub-query, you can join the results to your Accounts Table
Perhaps something like this
Select A.*
From Accounts A
Join (Select * from [dbo].[udf-Str-Parse]('7781,5913,551949194,4919491,...,444131',',')) B
on A.Key_Value =A.ID
The UDF -- If 2016, There is a native parser.
CREATE FUNCTION [dbo].[udf-Str-Parse] (#String varchar(max),#delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
-- Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
-- Select * from [dbo].[udf-Str-Parse]('id26,id46|id658,id967','|')
Returns #ReturnTable Table (Key_PS int IDENTITY(1,1) NOT NULL , Key_Value varchar(max))
As
Begin
Declare #intPos int,#SubStr varchar(max)
Set #IntPos = CharIndex(#delimeter, #String)
Set #String = Replace(#String,#delimeter+#delimeter,#delimeter)
While #IntPos > 0
Begin
Set #SubStr = Substring(#String, 0, #IntPos)
Insert into #ReturnTable (Key_Value) values (#SubStr)
Set #String = Replace(#String, #SubStr + #delimeter, '')
Set #IntPos = CharIndex(#delimeter, #String)
End
Insert into #ReturnTable (Key_Value) values (#String)
Return
End

How to query for number of records in select with "group by" clause in JPA/EclipseLink?

Suppose you have a following JPA query:
select car.year, car.month, count(car) from Car car group by car.year, car.month
Before we query for results, we need to know how many records this query will return (for pagination, UI and so on). In other words we need something like this:
select count(*) from
(select car.year, car.month, count(car)
from Car car group by car.year)
But JPA/EclipseLink does not support subqueries in "from" clause. It there a way around it?
(Of course you can use plain SQL and native queries, but this is not an option for us)
A portable JPA solution:
select count(*) from Car c where c.id in
(select MIN(car.id) from Car car group by car.year, car.month)
You could also go with something like:
select COUNT(DISTINCT CONCAT(car.year, "#", car.month)) from car
but I expect this to be less performant due to operations with textual values.
What about:
select count(distinct car.year) from car
I have another approach to solve this issue . by using my approach you don't need to know the no of rows this query is going to return.
here it is your solution :-
you going to need two variables
1) pageNo (your page no should be 1 for first request to data base and proceeding request it should be incremental like 2 ,3 , 4 5 ).
2) pageSize.
int start = 0;
if(pageNo!=null && pageSize!=null){
start = (pageNo-1) * pageSize;
}else{
pageSize = StaticVariable.MAX_PAGE_SIZE; // default page size if page no and page size are missing
}
your query
em.createquery("your query ")
.setfirstResult(start)
.setMaxResult(pageSize)
.getResultList();
As #chris pointed out EclipseLink supports subqueries. But the subquery can't be the first one in the from-clause.
So I came up with the following workaround which is working:
select count(1) from Dual dual,
(select car.year, car.month, count(car)
from Car car group by car.year) data
count(1) is important as count(data) would not work
You have to add an entity Dual (If your database does not have a DUAL table, create one with just one record.)
This works but I still consider it a workaround that would only work if you allowed to create the DUAL table.
Simply you can use setFirstResult and setMaxResult to set record bound for query ,also use size of list to return count of records that query runs. like this :
Query query = em.createQuery("SELECT d.name, COUNT(t) FROM Department d JOIN
d.teachers t GROUP BY d.name");
//query.setFirstResult(5);
//query.setMaxResult(15); this will return 10 (from 5 to 15) record after query executed.
List<Object[]> results = query.getResultList();
for (int i = 0; i < results.size(); i++) {
Object[] arr = results.get(i);
for (int j = 0; j < arr.length; j++) {
System.out.print(arr[j] + " ");
}
System.out.println();
}
-----Updated Section------
JPA does not support sub-selects in the FROM clause but EclipseLink 2.4 current milestones builds does have this support.
See, http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#Sub-selects_in_FROM_clause
You can probably rewrite the query with just normal joins though.
Maybe,
Select a, size(a.bs) from A a
or
Select a, count(b) from A a join a.bs b group by a
I hope this helps you.

Using EXISTS in hibernate to return one row only for performance(without setMaxResult)

I have to print a message if ANY duplicate row with same ID (not a primary KEY) exists in table (very large table), that meets a where clause.
Table Person is (There is no Index on table)
PersonPrimaryKEY PersonName ID Email Address InvoiceID TaxID
1 Bob 1 bob#example.com 1/Harton st 1 1
2 John 2 john#example.com 2/Harton st 2 2
3 Peter 1123 peter#example.com 3/Harton st 3 3
I used hibernate
public Collection<Person> readByNameAndID (String name, String ID)
{
TypedQuery<Person> q = getEntityManager ().createNamedQuery("Select p FROM Person p WHERE Name =:Name AND ID <> :ID", Person.class);
q.setParameter ("Name", Name);
q.setParameter ("ID", ID);
return q.getResultList ();
}
Code to use is
if(results.size > 0)
{
System.out.println("Error exists");
}
Problem is, it is very inefficient when reading large table.
How can I make it very efficient ? I was thinking of using EXISTS or COUNT to do that but how to incorporate it with hibernate so that it returns only ONE row then I check size > 0, which will be efficient.
Or is setMaxResult only solution of that ?
Thanks
Aiden
Since you are considering records duplicate on the basis of having the same PersonName, the following HQL query should do the trick:
SELECT COUNT(p)
FROM Person p
GROUP BY p.PersonName
HAVING COUNT(p) > 1
If the count from this query is greater than 0, it means you have duplicates present.

HQL: Counting a child collection conditionally within a query

I'm fairly inexperienced when it comes to HQL, so I was wondering if anyone can help me out on this. I have a relationship where Student has a OneToMany relationship with StudentCollege. I'm trying to write a query that finds each student who has made an application, and how many applications they've submitted. I have the following query written, but I am unsure if it's even close to what I should be doing.
select distinct new ReportVO (stu.id, stu.first_name, stu.last_name, stu.year, stu.school.school_name, sum(case when si.applied = 1 then 1 else 0 end) as numApplications) " +
"from StudentCollege as si join si.student as stu where stu.year <= 12 and stu.user.id = :userId and si.applied = 1 order by stu.last_name
When it runs the following exception is thrown:
org.hibernate.hql.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [package.location.ReportVO] [select distinct new ReportVO (stu.id, stu.first_name, stu.last_name, stu.year, stu.school.school_name, sum(case when si.applied = 1 then 1 else 0 end) as numApplications) from package.location.StudentCollege as si join si.student as stu where stu.year <= 12 and stu.user.id = :userId and si.applied = 1 order by stu.last_name]
However I have a constructor for the VO object that takes in that same number of arguments, so I'm thinking the type returned from the sum is incorrect. I've also tried replacing numApplications with Integer and Count, but the same exception is thrown.
public ReportVO(int id, String firstName, String lastName, int year, String school, Integer numApplications)
Any help is appreciated!
I believe you are a missing a "group by" clause after the where clause.
select distinct new ReportVO (stu.id, stu.first_name, stu.last_name, stu.year, stu.school.school_name, sum(case when si.applied = 1 then 1 else 0 end) as numApplications) " +
"from StudentCollege as si join si.student as stu where stu.year <= 12 and stu.user.id = :userId and si.applied = 1 group by stu.id, stu.first_name, stu.last_name, stu.year, stu.school.school_name order by stu.last_name

Categories