JPA Criteria: is it possible to join two queries? - sql

I have a query that is used to order messages by the total number of errors. Every message can have multiple instances. In this case I want to order by the total number of instances which have plausibility or integrity errors.
SELECT *
FROM t_message m
LEFT JOIN (
SELECT m.id, COUNT(*) AS count
FROM t_message m
LEFT JOIN t_alteration_instance i ON i.c_message_id = m.id
WHERE i.c_current_step_status = "INTEGRITY_ERROR" OR
i.c_current_step_status= "PLAUSIBILITY_ERROR"
GROUP BY m.id
) AS cnt ON cnt.id = m.id
ORDER BY count DESC
This query works in SQL, but how can I translate this to the criteria API, how can I join two queries or is there any other way?

Related

How do I filter out SELECT results from tables?

I have three tables that have user name/id and how many tasks they have submitted. I'm trying to SELECT user.name and the max amount of submissions they have for a single task.
SELECT DISTINCT O.nimi, COUNT(T.id)
FROM Opiskelijat O
LEFT JOIN Lahetykset L ON O.id = L.opiskelija_id
LEFT JOIN Tehtavat T ON T.id = L.tehtava_id
GROUP BY O.id, L.tehtava_id
The first picture shows the tables in question. In the second picture the above is what I'm trying to get, and the bottom is what my code does at the moment. I'm trying to get it to only show Maija - 3 instead of both.
Maybe somehing like this:
SELECT O.nimi, COUNT(*)
FROM Opiskelijat O
LEFT JOIN Lahetykset L ON O.id = L.opiskelija_id
LEFT JOIN Tehtavat T ON T.id = L.tehtava_id
GROUP BY O.id, O.nimi
As was pointed out, you need to have all the selected output fields in the GROUP BY. And also the DISTINCT should not be needed. I think the problem was the group by on L.tehtava_id.
If you want one row per nimi that should be the only column in the GROUP BY. I think you want:
SELECT O.nimi, COUNT(T.id)
FROM Opiskelijat O LEFT JOIN
Lahetykset L
ON O.id = L.opiskelija_id LEFT JOIN
Tehtavat T
ON T.id = L.tehtava_id
GROUP BY O.nimi;
I suspect that you don't actually need the join to Tehtavat:
SELECT O.nimi, COUNT(L.tehtava_id)
FROM Opiskelijat O LEFT JOIN
Lahetykset L
ON O.id = L.opiskelija_id
GROUP BY O.nimi;

How to have SQL query with 2 subqueries divided

I have a database which has these tables:
Users (id, email)
Trips (id, driver_id)
MatchedTrips (id, trip_id)
I need to get for each user the total number of trips he created divided by the total matches found.
I am stuck in building the raw SQL query for this. Here is what I tried, and sure it's far from being correct.
SELECT
users.email,
total_trips.count1 / total_matches.count2
FROM users CROSS JOIN (SELECT
users.email,
count(trips.driver_id) AS count1
FROM trips
INNER JOIN users ON trips.driver_id = users.id
GROUP BY users.email) total_trips
CROSS JOIN (SELECT users.email, count(matches.trip_id) AS count2
FROM matches
LEFT JOIN trips ON matches.trip_id = trips.id
LEFT JOIN users ON trips.driver_id = users.id
GROUP BY users.email) total_matches;
You can calculate total trips and total matches for each driver in the way like this:
select driver_id, count(t.id) as total_trips, count(m.id) as total_matches
from trips t
left join matches m on (t.id = trip_id)
group by 1
Use this query as a derived table in join with users:
select email, total_trips, total_matches, total_trips::dec/ nullif(total_matches, 0) result
from users u
left join (
select driver_id, count(t.id) as total_trips, count(m.id) as total_matches
from trips t
left join matches m on (t.id = trip_id)
group by 1
) s on u.id = driver_id
order by 1;
SQLFiddle.
The simplest way is probably to use count(distinct):
select u.email,
count(distinct t.id) as num_trips,
count(distinct m.id) as num_matches,
(count(distinct t.id) / count(distinct m.id)) as ratio
from users u left join
trips t
on t.driver_id = u.id left join
matches m
on m.trip_id = t.trip_id
group by u.email;
Note: If emails are unique, then the query can be simplified. count(distinct) can be expensive under some circumstances.

Counting associations from multiple tables

I want to see how many association each of my records in a given table have. Some of these association have some conditions attached to them
So far I have
-- Count app associations
SELECT
distinct a.name,
COALESCE(v.count, 0) as visitors,
COALESCE(am.count, 0) AS auto_messages,
COALESCE(c.count, 0) AS conversations
FROM apps a
LEFT JOIN (SELECT app_id, count(*) AS count FROM visitors GROUP BY 1) v ON a.id = v.app_id
LEFT JOIN (SELECT app_id, count(*) AS count FROM auto_messages GROUP BY 1) am ON a.id = am.app_id
LEFT JOIN (
SELECT DISTINCT c.id, app_id, count(c) AS count
FROM conversations c LEFT JOIN messages m ON m.conversation_id = c.id
WHERE m.visitor_id IS NOT NULL
GROUP BY c.id) c ON a.id = c.app_id
WHERE a.test = false
ORDER BY visitors DESC;
I run into problem with the last join statement for conversations. I want to count the number of conversations that have at least 1 message where the visitor_id is not null. For some reason, I get multiple records for each app, ie. the conversations are not being grouped properly.
Any ideas?
My gut feeling, based on limited understanding of the big picture: in the nested query selecting from conversations,
remove DISTINCT
remove c.id from SELECT list
GROUP BY c.app_id instead of c.id
EDIT: try this
...
LEFT JOIN (
SELECT app_id, count(*) AS count
FROM conversations c1
WHERE
EXISTS (
SELECT *
FROM messages m
WHERE m.conversation_id = c1.id and
M.visitor_id IS NOT NULL
)
GROUP BY c1.app_id) c
ON a.id = c.app_id

Dividing Count from Query of count in SQL

I am trying to essentially divide one count by a number I query from another table in SQL
MOVIECOUNT AS (
SELECT COUNT(MS.MOVID) AS MOVCOUNT, MG.GENRE AS GENREPERCOUNT
FROM MOVIESUCCESS MS
INNER JOIN MOVIES_GENRES MG ON MG.MOVIE_ID = MS.movid
group by MG.GENRE
)
SELECT (MC.MOVCOUNT / COUNT(DG.MOVIE_ID))
FROM MOVIECOUNT MC, DIRECTORS_GENRES DG
WHERE MC.GENREPERCOUNT = DG.GENRE
GROUP BY DG.GENRE
I can't get the latter part to compile (the MOVIECOUNT works--just there for reference). The rest of the schema isn't that important, and I have the rest of the code working.
I'm essentially just trying to get the count I found in moviecount (which is done per genre) and divide that by the count of all movies of the same genre. Ideas? Oracle SQL
You probably need to compute each aggregate separately before joining them:
with mgc as (
select
mg.genre,
count(*) as moviecount
from
moviesuccess ms
inner join
movies_genres mg
on mg.movie_id = ms.movid
group by
mg.genre
), dgc as (
select
dg.genre,
count(*) as directorcount
from
directors_genres dg
group by
dg.genre
) select
mgc.genre,
mgc.moviecount / dgc.directorcount
from
mgc
inner join
dgc
on mgc.genre = dgc.genre;
You can do this with the approach you are taking, you just have to be more careful with the aggregation:
WITH MOVIECOUNT AS (
SELECT COUNT(MS.MOVID) AS MOVCOUNT, MG.GENRE AS GENREPERCOUNT
FROM MOVIESUCCESS MS INNER JOIN
MOVIES_GENRES MG
ON MG.MOVIE_ID = MS.movid
group by MG.GENRE
)
SELECT (MC.MOVCOUNT / COUNT(DG.MOVIE_ID))
FROM MOVIECOUNT MC JOIN
DIRECTORS_GENRES DG
ON MC.GENREPERCOUNT = DG.GENRE
GROUP BY MC.GENRE, MC.MOVCOUNT;

SQL subselect group function not allowed

I'm facing a problem with an SQL subquery: I need to write a query which returns the courses where the number of subscriptions (count(employeeNumber)) is greater than the maximum allowed number of subscriptions (Maximum).
In my original query I'm getting following error:
Group function is not allowed here.
The query:
SELECT c.CourseName
FROM courses c
INNER JOIN subscriptions s ON s.courseCode = c.CourseCode
INNER JOIN plannedCourses p ON p.CourseCode = s.CourseCode
WHERE COUNT(s.EmployeeNumber) > (SELECT maximum
FROM plannedCourses
WHERE s.CourseCode = p.CourseCode);
The table layout:
How can i achieve the desire result?
Thanks in advance!!
You could rewrite your query as follows:
select c.coursename
from courses c
join subscriptions s
on (s.coursecode = c.coursecode)
join PlannedCourses p
on (p.coursecode = c.coursecode)
group by c.coursename
, p.maximum
having count(s.Employeenumber) > p.maximum
Your query has multiple problems. You are using a correlated subquery, but you are not using the table in its from clause. I think the intention is this:
SELECT c.CourseName
FROM courses c
INNER JOIN subscriptions s ON s.courseCode = c.CourseCode
group by c.CourseName, c.CourseCode
having COUNT(s.EmployeeNumber) > (SELECT "maximum"
FROM plannedCourses p
WHERE c.CourseCode = p.CourseCode);