SQL subselect group function not allowed - sql

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);

Related

SQL question on correlated sub-queries using windowing rank functions

I have this SQL homework assignment that tells me to list all the customers and the most recent DVD which they have rented, including the title, Genre, Rating, DVD and date of rental. This can be solved via a correlated sub-query or a window rank function
Here is a screenshot of the schema:
Here is what I have tried so far:
Select
Concat(m.MemberFirstName, ' ', m.MemberLastName) as Member
, d.DvdTitle
, g.GenreName
, rt.RatingName
, r.RentalRequestDate
From
Member m
Inner Join
RentalQueue rq on m.MemberId = rq.MemberId
Inner Join
DVD d on d.DVDId = rq.DVDId
Inner Join
Genre g on g.GenreId = d.GenreId
Inner Join
Rating rt on rt.RatingId = d.RatingId
Inner Join
Rental r on r.DVDId = d.DVDId
I am not sure how I can use correlated subqueries to answer the question above as I am quite new to correlated subqueries and I would appreciate some help on this. Thanks in advance.
Try something like this, but please try to understand it too.
Select
Concat(m.MemberFirstName, ' ', m.MemberLastName) as Member
, mostrecent.*
From
Member m
CROSS APPLY
(select top (1)
d.DvdTitle
, g.GenreName
, rt.RatingName
, r.RentalRequestDate
FROM
RentalQueue rq
Inner Join
DVD d on d.DVDId = rq.DVDId
Inner Join
Genre g on g.GenreId = d.GenreId
Inner Join
Rating rt on rt.RatingId = d.RatingId
Inner Join
Rental r on r.DVDId = d.DVDId
where m.MemberId = rq.MemberId
order by r.RentalRequestDate desc
) mostrecent

JPA Criteria: is it possible to join two queries?

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?

Returning multiple aggregated columns from Subquery

I am trying to extend an existing query by aggregating some rows from another table.
It works when I only return one column like this:
Select DISTINCT
Contracts.id,
Contracts.beginTime,
Contracts.endTime,
Suppliers.name
(SELECT COUNT(p.id) from production as p where p.id_contract = Contracts.id)
FROM Contracts
LEFT JOIN Suppliers on Contracts.id = Suppliers.id_contract
Then I tried to add another column for the aggregated volume:
Select DISTINCT
Contracts.id,
Contracts.beginTime,
Contracts.endTime,
Suppliers.name
(SELECT COUNT(p.id), SUM(p.volume) from production as p where p.id_contract = Contracts.id)
FROM Contracts
LEFT JOIN Suppliers on Contracts.id = Suppliers.id_contract
However, this returns the following error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
I experimented a bit with the EXISTS keyword, but couldn't figure out how to make it work. Also I'm not sure whether this is the way to go in my case.
The desired output would be like so:
contract1Id, supplierInfoContract1, nrItemsContract1, sumVolumeContract1
contract2Id, supplierInfoContract2, nrItemsContract2, sumVolumeContract2
Instead of using DISTINCT and subqueries, use GROUP BY and normal joins to get the aggregates. And always use aliases, it will make your life easier:
SELECT
c.id,
c.beginTime,
c.endTime,
s.name,
COUNT(p.id) prod_count,
SUM(p.volume) prod_vol
FROM Contracts c
LEFT JOIN production p on p.id_contract = c.id
LEFT JOIN Suppliers s on c.id = s.id_contract
GROUP BY c.id, c.beginTime, c.endTime, s.name;
Another option is to APPLY the grouped up subquery:
SELECT DISTINCT
c.id,
c.beginTime,
c.endTime,
s.name,
p.prod_count,
p.prod_vol
FROM Contracts c
LEFT JOIN Suppliers s on c.id = s.id_contract
OUTER APPLY (
SELECT
COUNT(p.id) prod_count,
SUM(p.volume) prod_vol
FROM production p WHERE p.id_contract = c.id
GROUP BY ()
) p;
You can also use CROSS APPLY and leave out the GROUP BY (), this uses a scalar aggregate and returns 0 instead of null for no rows.
One last point: DISTINCT in a joined query is a bit of a code smell, it usually indicates the query writer wasn't thinking too hard about what the joined tables returned, and just wanted to get rid of duplicate rows.
You should use it like below:
Select DISTINCT Contracts.id, Contracts.beginTime, Contracts.endTime, Suppliers.name
(SELECT COUNT(p.id) from production as p where p.id_contract = Contracts.id) as CNT,
(SELECT SUM(p.volume) from production as p where p.id_contract = Contracts.id) as VOLUME
FROM Contracts
LEFT JOIN Suppliers on Contracts.id = Suppliers.id_contract
I guess you can try to rework your query as
SELECT X.ID,X.beginTime,X.endTime,X.name,CR.CNTT,CR.TOTAL_VOLUME
FROM
(
Select DISTINCT Contracts.id, Contracts.beginTime, Contracts.endTime, Suppliers.name
FROM Contracts
LEFT JOIN Suppliers on Contracts.id = Suppliers.id_contract
)X
CROSS APPLY
(
SELECT COUNT(p.id)AS CNTT,SUM(p.volume) AS TOTAL_VOLUME
from production as p where p.id_contract = X.id
)CR
I reworked you query slightly by separating the subqueries.
Select DISTINCT
Contracts.id,
Contracts.beginTime,
Contracts.endTime,
Suppliers.name,
(SELECT COUNT(p.id) from production as p where p.id_contract = Contracts.id) count_id,
(SELECT SUM(p.volume) from production as p where p.id_contract = Contracts.id) sum_volume
FROM Contracts
LEFT JOIN Suppliers on Contracts.id = Suppliers.id_contract

Multiple joins with group by (Sum)

When I using multiple JOIN, I hope to get the sum of some column in joined tables.
SELECT
A.*,
SUM(C.purchase_price) AS purcchase_total,
SUM(D.sales_price) AS sales_total,
B.user_name
FROM
PROJECT AS A
LEFT JOIN
USER AS B ON A.user_idx = B.user_idx
LEFT JOIN
PURCHASE AS C ON A.project_idx = C.project_idx
LEFT JOIN
SALES AS D ON A.project_idx = D.project_idx
GROUP BY
????
You need to use subquery as follows:
SELECT A.project_idx,
a.project_name,
A.project_category,
sum(C.purchase_price) AS purcchase_total,
sum(D.sales_price) as sales_total,
B.user_name
FROM PROJECT AS A
LEFT JOIN USER AS B ON A.user_idx = B.user_idx
LEFT JOIN (select project_idx, sum(purchase_price) as purchase_price
from PURCHASE group by project_idx ) AS C ON A.project_idx = C.project_idx
LEFT JOIN (select project_idx, sum(sale_price) as sale_price
from SALES group by project_idx) AS D ON A.project_idx = D.project_idx
I am not sure but you can use inner join of project with user instead of left join.
SELECT A.project_idx,
a.project_name,
A.project_category,
purcchase_total,
sales_total,
B.user_name
FROM PROJECT AS A
LEFT JOIN USER AS B ON A.user_idx = B.user_idx
LEFT JOIN (select project_idx, sum(purchase_price) as purchase_total
from PURCHASE group by project_idx ) AS C ON A.project_idx = C.project_idx
LEFT JOIN (select project_idx, sum(sale_price) as sale_total
from SALES group by project_idx) AS D ON A.project_idx = D.project_idx
This is working correctly on MS-SQL Server.
Thanks to Popeye
You are attempting to aggregate over two unrelated dimensions, and that throws off all the calculations.
Correlated subqueries are an alternative:
SELECT p.*,
(SELECT SUM(pu.purchase_price)
FROM PURCHASE pu
WHERE p.project_idx = pu.project_idx
) as purchase_total,
(SELECT SUM(s.sales_price)
FROM SALES s
WHERE p.project_idx = s.project_idx
) as sales_total,
u.user_name
FROM PROJECT p LEFT JOIN
USER u
ON p.user_idx = u.user_idx ;
Note that this uses meaningful table aliases so the query is easier to read. Arbitrary letters are really no better (and perhaps worse) than using the entire table name.
Correlated subqueries avoid the outer aggregation as well -- and let you select all the columns from the first table, which is what you want. They also often have better performance with the right indexes.

SELECT COLUMNS FROM INNER JOIN

I wanted to select two columns from inner join of two select queries. I have written a query joining three tables and from the result I want to get only two column. But my query is showing error.I am using oracle sql developer.
SELECT firstname,surname
FROM (
SELECT A.firstname,A.surname,I.ACNUM,I.FIELDNUM
FROM ACADEMIC A INNER JOIN INTEREST I
ON (A.ACNUM = I.ACNUM)
INNER JOIN SUBJECT S ON (I.FIELDNUM = S.FIELDNUM) WHERE S.TITLE = 'History' ) ;
I want only the firstname and surname but I am getting error like:
Incorrect syntax near ';'.
Why are you using a subselect? Just use:
SELECT A.firstname, A.surname
FROM ACADEMIC A INNER JOIN
INTEREST I
ON A.ACNUM = I.ACNUM INNER JOIN
SUBJECT S
ON I.FIELDNUM = S.FIELDNUM
WHERE S.TITLE = 'History' ;
When you select from query you should name it as well.
Try this:
SELECT D.firstname,D.surname
FROM (SELECT A.firstname,A.surname,I.ACNUM,I.FIELDNUM
FROM ACADEMIC A
INNER JOIN INTEREST I ON (A.ACNUM = I.ACNUM)
INNER JOIN SUBJECT S ON (I.FIELDNUM = S.FIELDNUM)
WHERE S.TITLE = 'History') D;