Counting distinct values output from a grouped SQL Count function - sql

I've got a database that holds information about volunteers and their participation in a range of events.
The following query gives me a list of their names and total attendances
SELECT
volunteers.last_name,
volunteers.first_name,
count (bookings.id)
FROM
volunteers,
bookings
WHERE
volunteers.id = bookings.volunteer_id
GROUP BY
volunteers.last_name,
volunteers.first_name
I want the result table to show the distinct number of attendances and how many there are of each; So if five people did one event it'd display 1 in the first column and 5 in the second and so on.
Thanks

If I understand correctly, you want what I call a "histogram of histograms" query:
select numvolunteers, count(*) as numevents, min(eventid), max(eventid)
from (select b.eventid, count(*) as numvolunteers
from bookings b
group by b.eventid
) b
group by numvolunteers
order by numvolunteers;
The first column is the number of volunteers booked for an "event". The second is the number of events where this occurs. The last two columns are just examples of events that have the given number of volunteers.

Related

How to get Max from Count in SQL (Access)?

There is a table called "Athletes" which has columns for "Group" and "Award". It is necessary to calculate using Count the number of awards in groups separately and display the group with the maximum number of awards and the number of awards for this group. I tried to make a request of this type:
SELECT Max (Reward1) AS Reward
FROM (
SELECT Count (Athletes.Reward) AS Reward1
FROM Athletes
GROUP BY Athletes.Group
) AS [% $ ## # _ Alias];
This works, but the column corresponding to the maximum number of awards is not displayed for the group that received these awards. Can you please tell me what is worth adding so that this column is also displayed?
You're not selecting the GROUP column. You don't need to nest the query in a subquery, you can just pull the largest count of athlete rewards by selecting the largest row from your query.
SELECT TOP 1 Athletes.Group as Group
, Count (Athletes.Reward) AS Reward1
FROM Athletes
GROUP BY Athletes.Group
ORDER BY Reward1 DESC;

SQL QUERY : Find for each year copies sold > 10000

I am practicing a bit with SQL and I came across this exercise:
Consider the following database relating to albums, singers and sales:
Album (Code, Singer, Title)
Sales (Album, Year, CopiesSold)
with a constraint of referential integrity between the Sales Album attribute and the key of the
Album report.
Formulate the following query in SQL :
Find the code and title of the albums that have sold 10,000 copies
every year since they came out.
I had thought of solving it like this:
SELECT CODE, TITLE, COUNT (*)
FROM ALBUM JOIN SALES ON ALBUM.Code = SALES.Album
WHERE CopiesSold > 10000
HAVING COUNT(*) = /* Select difference from current year and came out year.*/
Can you help me with this? Thanks.
You can do this with an INNER JOIN, GROUP BY, and HAVING.
SELECT A.Code, A.Title
FROM ALBUM A
INNER JOIN SALES S ON S.Album = A.Code
GROUP BY A.Code, A.Title
HAVING MIN(S.CopiesSold) >= 10000
The HAVING clause will filter out albums whose minimum Copies Sold are < 10000.
EDIT
There was also a question about gaps in the Sales data, there are a number of ways to modify the above query to solve for this as well. One solution would be to use an embedded query to identify the correct number of years.
SELECT A.Code, A.Title
FROM ALBUM A
INNER JOIN SALES S ON S.Album = A.Code
GROUP BY A.Code, A.Title
HAVING MIN(S.CopiesSold) >= 10000 AND
COUNT(*) = (SELECT COUNT(DISTINCT Year) FROM SALES WHERE Year >= MIN(s.Year))
This solution assumes that at least one album by some artist was sold each year (a fairly safe bet). If you had a Years table there are simpler solutions. If the data is current there are also solutions that utilize DATEDIFF.
You can use correlated subqueries with EXISTS or NOT EXISTS respectively.
In one check if the maximum year minus the minimum year plus one is equal to the count of records with a defined year of an album. That way you make sure you don't get albums where there are figures missing for a year and you therefore cannot tell whether they sold 10000 or more or not. Also check that the maximum year is the current year not to miss gaps between the maximum year and the current year. (In the example code I will use the literal 2020 but there are means to get that dynamically. They depend on the DBMS however and you didn't state which one you're using.)
In the second one check that there's no record with undefined sales figures or sales figures lower than 10000 for the album. If no such record exists, all of the existing one have to have figures of 10000 or greater.
SELECT a1.code,
a1.title
FROM album a1
WHERE EXISTS (SELECT ''
FROM sales s1
WHERE s1.album = a1.code
HAVING max(s1.year) - min(s1.year) + 1 = count(s1.year)
AND max(s1.year) = 2020)
AND NOT EXISTS (SELECT *
FROM sales s2
WHERE s2.album = a1.code
AND s2.copiessold IS NULL
OR s2.copiessold < 10000);
I think the ALL keyword should work nicely here. Something like this:
SELECT * FROM Album
WHERE 10000 <= ALL (
SELECT CopiesSold FROM Sales
WHERE Sales.Album = Album.Code)

Joining Tables to Get Sums - SQL/Access

I am create an Access database at work for our call center. Right now there are four tables:
MASTERTABLE: DisplayName, CLOCKid (PrimaryKey), PHONEid
ROSTERTABLE: CLOCKid (ForeignKey), StartDate, EndDate
PHONELOG: PHONEid, DateStamp, StatusHours
TIMECLOCK: CLOCKid, DateStamp, HoursByDay
The Mastertable has one row for each unique employee. It contains each employee's various IDs/usernames for things listed above and other items. The Rostertable contains a row for each employee's position--an employee can have multiple positions over time, indicated by StartDate and EndDate, thus multiple rows. This is so we keep a historical record we can query. The PhoneLog is fed in from our phone system. It has multiple lines per user, representing each phone status the the amount of time the user spent in the status. The TimeClock is similar; An employee will have one row per day worked.
I need to create a query in Microsoft Access 2013, preferably using SQL, that will give me the Sum of everyone's TimeClock hours within their rostertable start/end times as well as the same for their phone hours. So the resulting query will list each employee from the RosterTable, the sum of their phone time, and the sum of their paid time.
Hope this makes sense. Let me know if anyone has questions/need clarification.
SELECT MT.DisplayName, Sum(PL.StatusHours) as PhoneHours, Sum(TC.HoursByDay) as PaidTime
FROM MASTERTABLE MT
INNER JOIN ROSTERTABLE RT
ON MT.ClockID = RT.ClockID
LEFT JOIN PHONELOG PL
ON MT.PhoneID = PL.PhoneID
LEFT JOIN TIMECLOCK TC
ON MT.ClockID = TC.ClockID
WHERE RT.StartDate >= YourStartDate
AND RT.EndDate =< YourEndDate
You just have to define YourStartDate and YourEndDate, which could be text boxes on a form or input boxes in a query, or even inner joined from another table.

sql-server-2008 : get the last status of subjects of a student

Salam, (Greetings) to all.
Intro:
I am working on a Student Examination System, where Students appear and pass or fail or absent.
Problem:
I am tasked to fetch their Summary of Status. you may say a Result Card which should print their very last status of a Subject.
Below is a sample of the data where a student has appeared many times, in different sessions. I have highlighted one subject in which a student has appeared three times.
Now, I write the following Query which extract the same result as the picture above:
SELECT DISTINCT
gr.STUDKEY,gr.SUBJECT_ID, gr.SUBJECT_DESC,gr.MARKS,
gr.PASSFAIL, gr.GRADE,max(gr.SESSION_ID), gr.LEVEL_ID
FROM RESULT gr
WHERE gr.STUDKEY = '0100106524'
GROUP BY gr.STUDKEY,gr.SUBJECT_ID, gr.SUBJECT_DESC,gr.MARKS,
gr.PASSFAIL, gr.GRADE, gr.LEVEL_ID
Desired:
I want to get only the last status of a subject in which a student has appeared.
Help is requested. Thanks in advanced.
Regards
I am using sql-server-2008.
This won't work because you include fields like gr.MARKS and gr.GRADE in the group by and in the select which means that the query might return more than 1 record for each session id while their grade or marks is different.
SELECT
gr.STUDKEY,gr.SUBJECT_ID, gr.SUBJECT_DESC,
gr.PASSFAIL, gr.GRADE,gr.SESSION_ID, gr.LEVEL_ID
FROM RESULT gr
JOIN (SELECT MAX(SessionId) as sessionId, STUDKEY
FROM RESULT
GROUP BY STUDKEY ) gr1 ON gr1.sessionId=gr.sessionid AND gr1.STUDKEY =gr.STUDKEY
Hopefully there is a date field, or something that indicates the order of the students appearances in this class. Use that to order your query in descending order, so that the most recent occurrence is the first record, then specifiy "Top 1" which will then give you only the most recent record for that student, which will include in his most recent status.
SELECT TOP 1
gr.STUDKEY,gr.SUBJECT_ID, gr.SUBJECT_DESC,gr.MARKS,
gr.PASSFAIL, gr.GRADE,gr.SESSION_ID, gr.LEVEL_ID
FROM RESULT gr
WHERE gr.STUDKEY = '0100106524'
ORDER BY gr.Date DESC //swap "Date" out for your field indicating the sequence.
or use a Group by with MAX(Date) if you're looking for multiple classes with the same student at the same time.

Need to add up all the hours for selected column

I'm trying to calculate training hours for a list of three departments but I'm not doing the query quite right. The column with the amount of hours is called tEmpCourseDetail.AuthRelTime (AuthorizedReleaseTime). But the below gives me four separate rows. What I want is it to calculate the values in all four rows.
SELECT SUM(AuthRelTime) AS trainingHours
FROM tEmpCourseAssoc
JOIN tEmpCourseDetail ON tEmpCourseAssoc.ECAssocID = tEmpCourseDetail.ECAssocID
WHERE AccountNumber IN ('760413','760416','767601')
GROUP BY AuthRelTime
What I want is it to return these added up. Which would be 15.
Is the group by needed at all? Try taking it out?
i.e.
SELECT SUM(AuthRelTime) AS trainingHours
FROM tEmpCourseAssoc
INNER JOIN tEmpCourseDetail ON tEmpCourseDetail.ECAssocID = tEmpCourseAssoc.ECAssocID
WHERE AccountNumber IN ('760413','760416','767601')