Is it possibile to perform JOIN in JPQL? - jpql

I'm using Objectdb, an object database, to save Cars to rent and requests for rental.
When one customers ask for a rental of a car, I have to check if the car is available in that period (from start date to end date). In my database I have two tables (two classes): car and rent. This is the query to check if the car is available:
public List<Car> findByType(CarType type, Date start, Date end) {
TypedQuery<Car> query = em.createQuery("SELECT c FROM Car c, Rental r "
+ "WHERE c.type = :cartype AND "
+ "((r.start > :start AND r.start > :end) OR "
+ "(r.end < :start AND r.end < :end))", entityClass);
...
The problem is that this query always return 0 cars available.
Is there a problem with a JOIN in JPQL? Or, is the query bad formed?
thank you

The query is not a valid JOIN query, because Car c and Rental r are not connected by the query.
But this doesn't explain why you get empty results. Try to isolate the problem by running smaller queries. For example, can you retrieve Rental objects by dates in a Rental only (no Car) query?

Related

Cassandra Modelling for Date Range

Cassandra Newbie here. Cassandra v 3.9.
I'm modelling the Travellers Flight Checkin Data.
My Main Query Criteria is Search for travellers with a date range (max of 7 day window).
Here is what I've come up with with my limited exposure to Cassandra.
create table IF NOT EXISTS travellers_checkin (checkinDay text, checkinTimestamp bigint, travellerName text, travellerPassportNo text, flightNumber text, from text, to text, bookingClass text, PRIMARY KEY (checkinDay, checkinTimestamp)) WITH CLUSTERING ORDER BY (checkinTimestamp DESC)
Per day, I'm expecting upto a million records - resulting in the partition to have a million records.
Now my users want search in which the date window is mandatory (max a week window). In this case should I use a IN clause that spans across multiple partitions? Is this the correct way or should I think of re-modelling the data? Alternatively, I'm also wondering if issuing 7 queries (per day) and merging the responses would be efficient.
Your Data Model Seems Good.But If you could add more field to the partition key it will scale well. And you should use Separate Query with executeAsync
If you are using in clause, this means that you’re waiting on this single coordinator node to give you a response, it’s keeping all those queries and their responses in the heap, and if one of those queries fails, or the coordinator fails, you have to retry the whole thing
Source : https://lostechies.com/ryansvihla/2014/09/22/cassandra-query-patterns-not-using-the-in-query-for-multiple-partitions/
Instead of using IN clause, use separate query of each day and execute it with executeAsync.
Java Example :
PreparedStatement statement = session.prepare("SELECT * FROM travellers_checkin where checkinDay = ? and checkinTimestamp >= ? and checkinTimestamp <= ?");
List<ResultSetFuture> futures = new ArrayList<>();
for (int i = 1; i < 4; i++) {
ResultSetFuture resultSetFuture = session.executeAsync(statement.bind(i, i));
futures.add(resultSetFuture);
}
for (ResultSetFuture future : futures){
ResultSet rows = future.getUninterruptibly();
//You get the result set of each query, merge them here
}

Count null columns as zeros with oracle

I am running a query with Oracle:
SELECT
c.customer_number,
COUNT(DISTINCT o.ORDER_NUMBER),
COUNT(DISTINCT q.QUOTE_NUMBER)
FROM
Customer c
JOIN Orders o on c.customer_number = o.party_number
JOIN Quote q on c.customer_number = q.account_number
GROUP BY
c.customer_number
This works beautifully and I can get the customer and their order and quote counts.
However, not all customers have orders or quotes but I still want their data. When I use LEFT JOIN I get this error from Oracle:
ORA-24347: Warning of a NULL column in an aggregate function
Seemingly this error is caused by the eventual COUNT(NULL) for customers that are missing orders and/or quotes.
How can I get a COUNT of null values to come out to 0 in this query?
I can do COUNT(DISTINCT NVL(o.ORDER_NUMBER, 0)) but then the counts will come out to 1 if orders/quotes are missing which is no good. Using NVL(o.ORDER_NUMBER, NULL) has the same problem.
Try using inline views:
SELECT
c.customer_number,
o.order_count,
q.quote_count
FROM
customer c,
( SELECT
party_number,
COUNT(DISTINCT order_number) AS order_count
FROM
orders
GROUP BY
party_number
) o,
( SELECT
account_number,
COUNT(DISTINCT quote_number) AS quote_count
FROM
quote
GROUP BY
account_number
) q
WHERE 1=1
AND c.customer_number = o.party_number (+)
AND c.customer_number = q.account_number (+)
;
Sorry, but I'm not working with any databases right now to test this, or to test whatever the ANSI SQL version might be. Just going on memory.

Sails.js One to many performances

I have compared the sql query on sails.js with the other way of doing it, using waterline's ORM.
I did the following request : Get all countries from all continents and I compared both requests with wireshark.
The simple SQL query :
"SELECT * FROM countries AS cou INNER JOIN continents AS con ON (cou.continent_id=continent.id)"
And then I did the same defining a one to many associations between countries and continents and did the following request.
Continents.find().populate("countries").exec(function(err, result)) {
res.send(result)
}
With that way, it takes around 66 ms to return the result, considering I have 15 ms of network delay, I can go down to 50 ms by moving the node.js server.
When I do it with the sql query, it takes around 35ms, so I could go down to nearly 20ms, which is good for me.
Is there a way to get the same results using both methods? or will the sql query always be faster?
Actually, the query generated in such population is
1. Selection of parents :
select * from continent where ...
Selection of all countries of the retrieved continents.
(select * from country where continent_id = continent_1)
union
(select * from country where continent_id = continent_2)
union
...
union
(select * from country where continent_id = continent_n)
Regroup result (Affectation of every country to its continent by foreign key.
This implementation make easy the management of limit and skip clauses as the call :
Continents.find().populate("countries").limit(2).skip(1).exec(function(err,
result)) {
res.send(result)
}
should only return the second and the third country for every continent and such implementation as you can see generate one only query so DBMS will not be overloaded.

JPQL result not what I want

Okay, so I have several tables
Vote
Contest
ContestSegment
ContestRegistration
Submittable
User
The relationship is that a Submittable may be submitted to a contest via creating a ContestRegistration, which is tied to a ContestSegment, which is tied to a Contest.
A Vote has a User and a reference to a ContestRegistration that the Vote relates to.
Pretty simple.
Now, the idea is that I want to hit a RESTful service which checks to see if I've already voted on one of the ContestRegistrations in a contest.
Everything is working except for the desired result.
The JPQL that I'm running looks like this:
SELECT DISTINCT v
FROM Vote v, Contest c
JOIN v.user vu
LEFT JOIN c.segments cs
LEFT JOIN cs.registrations csr
LEFT JOIN csr.votes csrv
WHERE vu.id = :userId
AND cs.beginDate < CURRENT_TIMESTAMP
AND cs.endDate > CURRENT_TIMESTAMP
AND c.id = :contestId
The method looks like:
public Boolean hasUserVoted(User user, Contest contest){
StringBuffer query = new StringBuffer()
.append("SELECT DISTINCT v from Vote v, Contest c ")
.append("JOIN v.user vu LEFT JOIN c.segments cs LEFT JOIN cs.registrations csr LEFT JOIN csr.votes csrv ")
.append("WHERE vu.id = :userId ")
.append(" ")
.append("AND cs.beginDate < CURRENT_TIMESTAMP AND cs.endDate > CURRENT_TIMESTAMP AND c.id = :contestId ");
Boolean hasVoted = true;
try{
Vote vote = (Vote)entityManager.createQuery(query.toString())
.setParameter("userId", user.getId())
.setParameter("contestId", contest.getId()).getSingleResult();
}catch(NoResultException nre){
hasVoted = false;
}
return hasVoted;
}
But when I return, no matter what I plug in, I'm always getting a true back (meaning I've already voted). For instance, I've voted on contest#1, but I haven't voted on contest#2. If I plug in the value for contest#2, then I still get a true back. I'm fairly new to JPQL, so any help you can provide would be awesome! Thanks!
With the use of left joins in your JPQL, it will return true unless the contest don't exists. Its sounds like the csr.votes should be a normal join.
You don't have any restriction linking the vote with the contest. I think your query should be :
SELECT DISTINCT v
FROM Contest c
JOIN c.segments cs
JOIN cs.registrations csr
JOIN csr.votes csrv
JOIN csrv.user vu
WHERE vu.id = :userId
AND cs.beginDate < CURRENT_TIMESTAMP
AND cs.endDate > CURRENT_TIMESTAMP
AND c.id = :contestId

How to make subquery fast

for an author overview we are looking for a query which will show all the authors including their best book. The problem with this query is that it lacks speed. There are only about 1500 authors and the query do generate the overview is currently taking 20 seconds.
The main problem seems te be generating the average rating of all the books per person.
By selecting the following query, it is still rather fast
select
person.id as pers_id,
person.firstname,
person.suffix,
person.lastname,
thriller.title,
year(thriller.orig_pubdate) as year,
thriller.id as thrill_id,
count(user_rating.id) as nr,
AVG(user_rating.rating) as avgrating
from
thriller
inner join
thriller_form
on thriller_form.thriller_id = thriller.id
inner join
thriller_person
on thriller_person.thriller_id = thriller.id
and thriller_person.person_type_id = 1
inner join
person
on person.id = thriller_person.person_id
left outer join
user_rating
on user_rating.thriller_id = thriller.id
and user_rating.rating_type_id = 1
where thriller.id in
(select top 1 B.id from thriller as B
inner join thriller_person as C on B.id=C.thriller_id
and person.id=C.person_id)
group by
person.firstname,
person.suffix,
person.lastname,
thriller.title,
year(thriller.orig_pubdate),
thriller.id,
person.id
order by
person.lastname
However, if we make the subquery a little more complex by selecting the book with the average rating it takes a full 20 seconds to generate a resultset.
The query would then be as follows:
select
person.id as pers_id,
person.firstname,
person.suffix,
person.lastname,
thriller.title,
year(thriller.orig_pubdate) as year,
thriller.id as thrill_id,
count(user_rating.id) as nr,
AVG(user_rating.rating) as avgrating
from
thriller
inner join
thriller_form
on thriller_form.thriller_id = thriller.id
inner join
thriller_person
on thriller_person.thriller_id = thriller.id
and thriller_person.person_type_id = 1
inner join
person
on person.id = thriller_person.person_id
left outer join
user_rating
on user_rating.thriller_id = thriller.id
and user_rating.rating_type_id = 1
where thriller.id in
(select top 1 B.id from thriller as B
inner join thriller_person as C on B.id=C.thriller_id
and person.id=C.person_id
inner join user_rating as D on B.id=D.thriller_id
group by B.id
order by AVG(D.rating))
group by
person.firstname,
person.suffix,
person.lastname,
thriller.title,
year(thriller.orig_pubdate),
thriller.id,
person.id
order by
person.lastname
Anyone got a good suggestion to speed up this query?
Calculating an average requires a table scan since you've got to sum the values and then divide by the number of (relevant) rows. This in turn means that you're doing a lot of rescanning; that's slow. Can you calculate the averages once and store them? That would let your query use those pre-computed values. (Yes, it denormalizes the data, but denormalizing for performance is often necessary; there's a trade-off between performance and minimal data.)
It might be appropriate to use a temporary table as the store of the averages.

Resources