Trouble with integrating COUNT function in SQL query using Oracle - sql

I am trying to self educate myself in SQL in order to better use databases at work. For this purpose I am using Oracle Application Express. This if my first time using the COUNT function and I am having some difficulties integrating it within my query. I have done a great deal of research and read quite a bit of literature but I just can't seem to get it right.
My goal is to display the channel_name and channel_number columns (from the channel table) for each channel along with a count of the number of customers that have that channel as a favorite channel (survey_result column from the survey table). Please see below for code:
SELECT channel.channel_number,
channel.channel_name,
survey.survey_result,
count(SELECT survey.survey_result FROM survey)
From Channel, survey
WHERE survey.channel_number = channel.channel_number
Currently I am getting the error message:
ORA-00936: missing expression.

Try this:
Below query gives you only those channels which have minimum 1 customer.
SELECT C.channel_number, C.channel_name, COUNT(S.survey_result) NoOfCustomers
FROM Channel C
INNER JOIN survey S ON S.channel_number = C.channel_number
GROUP BY C.channel_number, C.channel_name;
And below query gives you all channels whether it has customer or not.
SELECT C.channel_number, C.channel_name, COUNT(S.survey_result) NoOfCustomers
FROM Channel C
LEFT JOIN survey S ON S.channel_number = C.channel_number
GROUP BY C.channel_number, C.channel_name;

Either of these may work for you
SELECT channel.channel_number,
channel.channel_name,
count(survey.survey_result)
From Channel, survey
WHERE survey.channel_number = channel.channel_number
GROUP BY
channel.channel_number,
channel.channel_name
or
SELECT channel.channel_number,
channel.channel_name,
survey.survey_result,
(SELECT count(survey_result) FROM survey)
From Channel, survey
WHERE survey.channel_number = channel.channel_number

count is an aggregate function thus you should have a group by on channel.channel_number and channel.channel_name. then just use count(survey.survey_result) instead of count(SELECT survey.survey_result FROM survey). Madhivanan's and Saharsh Shah's answers look good to me. including this answer to explain why.

Related

Use group by with sum in query

These 3 tables that you see in the image are related
Course table and coaching table and sales table
I want to make a report from this table on how much each coach has sold by each course period.
The query I created is as follows, but unfortunately it has a problem and I do not know where the problem is.
Please help me fix the problem
Thank you
SELECT
dbo.tblCustomersOrders.id, dbo.tblCustomersOrders.pid, dbo.tblPost.postTitle,
dbo.tblArticleAuthor.authorName, SUM(dbo.tblCustomersOrders.prodPrice) AS TotalBuys
FROM
dbo.tblPost
INNER JOIN
dbo.tblArticleAuthor ON dbo.tblPost.id = dbo.tblArticleAuthor.articleID
INNER JOIN
dbo.tblCustomersOrders ON dbo.tblPost.id = dbo.tblCustomersOrders.pid
GROUP BY dbo.tblCustomersOrders.pid
For this use, SUM() is an Aggregate Function, so you need to refer all the
fields that you want to get in your result set.
Example:
SELECT
dbo.tblCustomersOrders.id, dbo.tblCustomersOrders.pid, dbo.tblPost.postTitle,
dbo.tblArticleAuthor.authorName, SUM(dbo.tblCustomersOrders.prodPrice) AS TotalBuys
FROM dbo.tblPost
INNER JOIN
dbo.tblArticleAuthor ON dbo.tblPost.id = dbo.tblArticleAuthor.articleID
INNER JOIN
dbo.tblCustomersOrders ON dbo.tblPost.id = dbo.tblCustomersOrders.pid
GROUP BY dbo.tblCustomersOrders.id, dbo.tblCustomersOrders.pid,
dbo.tblPost.postTitle, dbo.tblArticleAuthor.authorName
But this query does not solve the need for your report.
If you just need to get "how much each coach has sold by each course" , you can try the query bellow.
SELECT
dbo.tblArticleAuthor.authorName, dbo.tblPost.postTitle,
SUM(dbo.tblCustomersOrders.prodPrice) AS TotalBuys
FROM dbo.tblPost
INNER JOIN
dbo.tblArticleAuthor ON dbo.tblPost.id = dbo.tblArticleAuthor.articleID
INNER JOIN
dbo.tblCustomersOrders ON dbo.tblPost.id = dbo.tblCustomersOrders.pid
GROUP BY dbo.tblArticleAuthor.authorName, dbo.tblPost.postTitle
If you need, send more details regarding the desired result.
Here you can find more information about SQL SERVER Aggregate Functions:
https://learn.microsoft.com/en-us/sql/t-sql/functions/aggregate-functions-transact-sql?view=sql-server-ver15
And here a quick example regarding SQL Aliases to build queries with a simple
and effective way:
https://www.w3schools.com/sql/trysql.asp?filename=trysql_select_alias_table
Per your description of the task, the problem is that you only GROUPed BY dbo.tblCustomersOrders.pid, which is the period's id I guess, but you also need to GROUP BY the coach, which is dbo.tblArticleAuthor.authorName, I guess again. Plus in the SELECT field list you can not use more columns only that are aggregated + GROUPed.

Convert a SQL query in Java Persistence Query Language (JPQL)

I'm having a little problem to convert this SQL query to JPQL:
select max(datePurchase) from purchases where userId = id and date_trunc('day',datePurchase)
in (select distinct (date_trunc('day',datePurchase)) as day from purchases where userId = id and datePurchase < initialDate and datePurchase > finalDate) group by date_trunc('day',datePurchase)
This sql is working well, that returns de last purchase per day made from a user. I tried to do the same, in JPQL:
Query query = em.createQuery("SELECT u MAX(u.datePurchase) FROM Purchases u WHERE u.userId.id = :id AND FUNC('day',u.datePurchase)" +
"IN (SELECT DISTINCT (FUNC('day',u.datePurchase)) AS day FROM Purchases WHERE u.userId.id = :id AND u.datePurchase < :finalDate AND u.datePurchase > :inicialDate) GROUP BY FUNC('day',u.datePurchase)");
query.setParameter("id", idUsuario);
query.setParameter("dataInicial", dataInicial);
query.setParameter("dataFinal", dataFinal);
List<MovSaldo> saldos = (List<MovSaldo>) query.getResultList();
em.getTransaction().commit();
The errors are:
"The IN expression does not have a valid expression." "An identification variable must be provided for a range variable declaration."
Probably is not something very difficult, but i have already spent a little frustrating time in it. Can someone please help me?
Although the answer is probably late for you I still posted it because it might help someone in the future.
In the nested select you have to put an identifier for the entity you are working with: FROM Purchases p and update things like (FUNC('day',u.datePurchase)) to (FUNC('day',p.datePurchase))
Best!

Select from two tables giving more rows than expected

I am not sure why this behaves this way. I need to select few values from two tables based on some criteria which should be clear from the query i tried below.
query = #"SELECT n.borrower, a.sum, n.lender FROM Notification AS n, Acknowledgment AS a
WHERE n.deleted=#del2 AND n.id IN (SELECT parent_id FROM Acknowledgment
WHERE status=#status AND deleted=#del1)";
This returns more rows (12) than expected.
I have two tables Notification and Acknowledgment both which have field "sum". When I try the query below it gives the correct 3 rows as expected.
#"SELECT n.borrower, n.sum, n.lender FROM Notification AS n
WHERE n.deleted=#del2 AND n.id IN (SELECT parent_id FROM Acknowledgment
WHERE status=#status AND deleted=#del1)";
Now I need to extend this query so that I need a.sum and not n.sum. But when I try the first query, it gives a lot more rows, I mean the WHERE condition doesn't work. I dunno if its a quirk with MS Access or something wrong with query. I appreciate an alternate implementation in access if my query seems fine 'cos it simply doesn't work! :)
I have read here that different databases implement select in different ways. Dunno if its something specific with access..
After suggestion from Li0liQ, I tried this:
#"SELECT n.borrower, a.sum, n.lender FROM Notification AS n
INNER JOIN Acknowledgment AS a ON a.parent_id = n.id AND a.status=#status AND a.deleted=#deleted1
WHERE n.deleted=#deleted2"
But I now get a "JOIN expression not supported" error.
This is expected behavior because of the cartesian product:
FROM Notification AS n, Acknowledgment AS a
If you have 10 notifications and 5 acknowledgements, you'll get 50 rows in the result, representing all possible combinations of a notification and an acknowledgement. That set is then filtered by the WHERE clause. (That's standard for SQL, not specific to MS Access.)
It sounds like you need a JOIN:
FROM Notification AS n INNER JOIN Acknowledgement AS a ON n.id = a.parent_id
You can then get rid of the subquery:
WHERE n.deleted=#del2 AND a.status=#status AND a.deleted=#del1
EDIT
As requested by nawfal, here is the solution he arrived at, which essentially incorporates the above recommendations:
string query = #"SELECT n.borrower, a.sum, n.lender FROM Notification AS n
INNER JOIN Acknowledgment AS a ON a.parent_id=n.id
WHERE a.status=#status AND a.deleted=#deleted1 AND n.deleted=#deleted2";
In first query you seem to be trying to perform a JOIN.
However you end up performing CROSS JOIN, i.e. you query for all possible combinations from both tables (I bet you have 4 rows in the Acknowledgment table).
I hope the following query could do the trick or at least help you think in the right direction:
SELECT
n.borrower, a.sum, n.lender
FROM
Notification AS n
INNER JOIN
Acknowledgment AS a
ON
a.parent_id = n.id
WHERE
n.deleted=#del2 AND a.status=#status AND a.deleted=#del1
Something seems to be wrong with Access, that I could get this working only by reconstructing the query provided by the answerers here this way:
string query = SELECT n.borrower, a.sum, n.lender FROM Notification AS n
INNER JOIN Acknowledgment AS a ON a.parent_id=n.id
WHERE a.status=#status AND a.deleted=#deleted1 AND n.deleted=#deleted2;

sqlzoo track join exercise

I've found a great site to practice sql - http://sqlzoo.net. my sql is very weak that is why i want to improve it by working on the exercises online. But i have this one problem that I cannot solve. can you please give me a hand.
3a. Find the songs that appear on more than 2 albums. Include a count of the number of times each shows up.
album(asin, title, artist, price, release, label, rank)
track(album, dsk, posn, song)
my answer is incorrect as i ran the query.
select a.song, count(a.song) from track a, track b
where a.song = b.song
a.album != b.album
group by a.song
having count(a.song) > 2
thanks in advance! :D
I realize this answer may be late but for future reference to anyone taking on this tutorial the answer is as such
SELECT track.song, count(album.title)
FROM album INNER JOIN track ON (album.asin = track.album)
GROUP BY track.song
HAVING count(DISTINCT album.title) > 2
Some things that my help you in your quest for this query is that what to group by is usually specified by the word each. As per the tip presented in the previous answers you want to select by distinct albums, SINCE it mentioned in the database description that album titles would be repeated when the two tables are joined
Your original answer is very close, with the GROUP BY and HAVING clause. What is wrong, is just that you don't need to join the track table against itself.
SELECT song, count(*)
FROM track
GROUP BY song
HAVING count(*) > 2
Another answer here uses COUNT(DISTNCT album), which is necessary only if a song can appear on an album more than once.
If they support nested querys, you can:
Select song, count(*)
from(
select a.song
from track a
group by a.song, a.album
having count(*) > 1
)
group by song
or(best way to write it)if they support this syntax:
select a.song, count(distinct a.album)
from track a
group by a.song
having count(distinct a.album) > 1

SQL count(), trying to count rows from two tables and restrict info displayed

I am setting up a database that has a limit to the amount of people that can register for a course. In my course table I have a Maximum column which holds an int and in my registered table it holds all the registered people for that course. SO my web page should only display course times where the number of registered people in the registered table < maximum allowed in the course table. Heres my current query.
SELECT course.time,COUNT(registered.time),registered.maximum FROM course
JOIN (registered)
ON course.type = 'computing' OR
(registered.type = 'computing' AND course.time = registered.time)
GROUP BY course.time
HAVING COUNT(registered.time) < course.maximum
The problem with this is it counts all the registered people regardless of the course time, so if there is 2 people registered for different times it still counts 2 people registered for each time.
Hope I explained it ok and hope someone can help. Thanks
It is unclear to me why you have registered.maximum and course.maximum. And it would be easier to answer the question if we knew the actual table structure, rather than having to guess based on your code. But here goes:
SELECT course.time, COUNT(registered.time), registered.maximum
FROM course
JOIN registered
ON course.type = registered.type
AND course.time = registered.time
WHERE course.type = 'computing'
GROUP BY course.time, registered.maximum
HAVING COUNT(registered.time) < course.maximum
I also did a group by on registered.maximum, because you will get a syntax error otherwise.
Finally, I changed the join to be on the type, and then added it to the WHERE clause. To me, that always makes more sense, though it may sometimes be slower. From my perspective, the JOIN clause is just for joining, while the WHERE clause is for filtering.
UPDATE: to also get courses with no one registered:
SELECT course.time, COUNT(registered.time), course.maximum
FROM course
LEFT OUTER JOIN registered
ON course.type = registered.type
AND course.time = registered.time
WHERE course.type = 'computing'
GROUP BY course.time, course.maximum
HAVING COUNT(registered.time) < course.maximum