SQL Finding Group where attendance less than average - sql

How can i get the number of attendees below average? This is my Oracle query
SELECT e.event_id EventID,c.concert_name ConcertName, c.concert_date,
AVG(e.attendance) Attendance
FROM event e INNER JOIN concert c ON c.concert_id = e.concert_id
WHERE Attendance - AVG(e.Attendance)
GROUP BY c.concert_id ASC;

Using the AVG(..) OVER () analytic function (and without a correlated sub-query):
SELECT eventId,
ConcertName,
Concert_Date
FROM (
SELECT e.event_id EventID,
c.concert_name ConcertName,
c.concert_date,
e.attendance,
AVG(e.attendance) OVER () AS avg_Attendance
FROM event e
INNER JOIN concert c
ON c.concert_id = e.concert_id
)
WHERE attendance < avg_attendance;

You can try with this way:
SELECT e.event_id EventID,c.concert_name ConcertName, c.concert_date,
AVG(e.attendance) Attendance
FROM event e INNER JOIN concert c ON c.concert_id = e.concert_id
WHERE e.attendance < (select AVG(ev.attendance) from event ev)
GROUP BY c.concert_id ASC;

Related

Select lowest number from column and show other columns

I need to find the lowest number in my RESULT column which I know can be done with MIN but I am not sure how to do this as well as select my other columns. My code displays all the results for all members but I just want it to show the best result (lowest number) along with the other details for that member.
Right now I have multiple entries that look like this:
EVENT_ID EVENT_TYPE EVENT_NAME MEMBER_ID MEMBER_FIRSTNAME MEMBER_LASTNAME RESULT
event1 track 100M 0001 John Smith 11.3
I just need to select the row with the lowest result and show that one only. Here is my code so far:
SELECT E.EVENT_ID, E.EVENT_TYPE, E.EVENT_NAME, R.MEMBER_ID, M.MEMBER_FIRSTNAME, M.MEMBER_LASTNAME, R.RESULT
FROM EVENT E, MEMBER M, RANK R
WHERE E.EVENT_ID = R.EVENT_ID
AND R.MEMBER_ID = M.MEMBER_ID;
SGEDDES - I tried following your last method and couldn't get it to work:
SELECT E.EVENT_ID, E.EVENT_TYPE, E.EVENT_NAME, R.MEMBER_ID, M.MEMBER_FIRSTNAME, M.MEMBER_LASTNAME, R.RESULT
FROM (EVENT E, MEMBER M, RANK R
WHERE E.EVENT_ID = R.EVENT_ID
AND R.MEMBER_ID = M.MEMBER_ID;
ORDER BY RESULT)
WHERE ROWNUM = 1;
Here's one option using row_number (also please note the join syntax -- in general you shouldn't use commas in the from clause):
SELECT *
FROM (
SELECT E.EVENT_ID, E.EVENT_TYPE, E.EVENT_NAME,
R.MEMBER_ID, M.MEMBER_FIRSTNAME, M.MEMBER_LASTNAME, R.RESULT,
row_number() over (order by R.RESULT) rn
FROM EVENT E JOIN RANK R ON E.EVENT_ID = R.EVENT_ID
JOIN MEMBER M ON R.MEMBER_ID = M.MEMBER_ID
) t
WHERE rn = 1
If you need to group the results by a specific field(s), you an use partition by. For example:
row_number() over (partition by e.event_id order by result) rn
And here's another option using rownum:
SELECT *
FROM (<<YOUR QUERY HERE>> ORDER BY R.Result )
WHERE ROWNUM = 1;
In the most recent versions of Oracle, you can use fetch first 1 row only:
SELECT E.EVENT_ID, E.EVENT_TYPE, E.EVENT_NAME, R.MEMBER_ID,
M.MEMBER_FIRSTNAME, M.MEMBER_LASTNAME, R.RESULT
FROM EVENT E JOIN
RANK R
ON E.EVENT_ID = R.EVENT_ID JOIN
MEMBER M
ON R.MEMBER_ID = M.MEMBER_ID
ORDER BY R.RESULT
FETCH FIRST 1 ROW ONLY;
If you have a less recent version of Oracle, then one of sgeddes's solutions is fine.

Find average score from event at specific meeting

I need to find the average score from everyone that took part in a high jump event at a specific event (ex event01)
My tables are MEETING, EVENT, RANK and my broken code is below:
SELECT *
FROM(
SELECT M.MEETING_ID, M.MEETING_NAME, E.EVENT_ID, E.EVENT_NAME,
ROW_NUMBER() OVER (ORDER BY R.RESULT) RN, (SELECT AVG(RESULT) FROM RANK WHERE E.EVENT_NAME = 'HIGH JUMP' AND M.MEETING_ID = 'MEET0002' ) AS HG
FROM MEETING M JOIN RANK R ON M.MEETING_ID = R.MEETING_ID
JOIN EVENT E ON E.EVENT_ID = R.EVENT_ID
)
WHERE RN = 1
Expected outcome:
MEETING_ID MEETING_NAME EVENT_ID EVENT_NAME AVERAGESCORE
meet01 sports day event01 high jump 10.6
Really appreciate any help!
This is just an aggregation query with filtering:
SELECT M.MEETING_ID, M.MEETING_NAME, E.EVENT_ID, E.EVENT_NAME,
AVG(RESULT) AS HG
FROM MEETING M JOIN
RANK R
ON M.MEETING_ID = R.MEETING_ID JOIN
EVENT E
ON E.EVENT_ID = R.EVENT_ID
WHERE E.EVENT_NAME = 'HIGH JUMP' AND M.MEETING_ID = 'MEET0002'
GROUP BY M.MEETING_ID, M.MEETING_NAME, E.EVENT_ID, E.EVENT_NAME;
You need the GROUP BY to include the first four columns in the result set.
Why filter at WHERE clause when you can filter things at JOIN itself.
SELECT M.MEETING_ID, M.MEETING_NAME, E.EVENT_ID, E.EVENT_NAME,
AVG(RESULT) over (partition by E.EVENT_ID) AS avg
FROM EVENT E
JOIN RANK R
ON E.EVENT_ID = R.EVENT_ID AND E.EVENT_ID = '001' AND E.EVENT_NAME='HIGH JUMP'
JOIN
MEETING M
ON M.MEETING_ID = R.MEETING_ID;

using count on when creating a view

im have a view that need to include the count of members volunteering for an event. I'm getting an error 'not a single-group group functions'. Any idea how to resolve this?
CREATE VIEW atbyrd.events__view AS
SELECT e.name, e."DATE", b."LIMIT",b.allocated_amount, COUNT(em.member_id), e.comments
FROM events e INNER JOIN budgets b ON b.event_id = e.id
INNER JOIN event_members em ON em.event_id = e.id;
SELECT e.name,
e."DATE",
b."LIMIT",
b.allocated_amount,
(select COUNT(member_id) from event_members) as mem_count,
e.comments
FROM events e
INNER JOIN budgets b ON b.event_id = e.id
INNER JOIN event_members em ON em.event_id = e.id;
You could use the analytic function count()
SELECT e.name
, e."DATE"
, b."LIMIT"
, b.allocated_amount
, COUNT(em.member_id) over ( partition by em.event_id )
, e.comments
FROM events e
INNER JOIN budgets b
ON b.event_id = e.id
INNER JOIN event_members em
ON em.event_id = e.id;
Simply put this counts the number of members per event_id but as it's not an aggregate function no GROUP BY is required. You receive the same value per event_id.

SQL Join to get most recent record

I have three tables:
Measurements (MeasureID, Time, Distance, Value)
Events(EventID, Time Value)
EventValues (EventDataID, EventID, Type, Value)
I need to get for every measurement, the most recent event (in the past) and its associated eventvalues data.
My current query is quite ugly:
SELECT
M.*,
(SELECT TOP 1 EV.value FROM [Event] E JOIN EventValues EV ON E.EventID = EV.EventID
WHERE M.Time >= E.Time ORDER BY M.Time-E.Time) AS Data,
FROM [Measure] M
ORDER BY M.Distance
and it only allows me to select one column from the EventValues table (I need more)
Is there any way this can be done using a join?
EDIT: I also need to select ALL entries from the measurement table even if they are before the first event (i.e. just select null data for the join)
You can use CROSS APPLY.
SELECT
M.*, Data.*
FROM [Measure] M
CROSS APPLY
(SELECT TOP 1 EV.* FROM [Event] E JOIN EventValues EV ON E.EventID = EV.EventID
WHERE M.Time >= E.Time ORDER BY E.Time DESC) AS Data
ORDER BY M.Distance
Try something like this (not tested)
SELECT * FROM
(
SELECT M.*, E.*, EV.EventDataID, EV.Type, EV.Value,
Rank() over (Partition BY M.MeasureID order by M.Time - E.Time) as Rank
FROM [Measure] M
INNER JOIN [Event] E ON M.Time >= E.Time
INNER JOIN EventValues EV ON E.EventID = EV.EventID
) T
WHERE Rank = 1
EDIT
SELECT * FROM
(
SELECT M.*, E.*, EV.EventDataID, EV.Type, EV.Value,
Rank() over (Partition BY M.MeasureID order by M.Time - E.Time) as Rank
FROM [Measure] M
LEFT JOIN [Event] E ON M.Time >= E.Time
LEFT JOIN EventValues EV ON E.EventID = EV.EventID
) T
WHERE Rank = 1

SQL LEFT OUTER JOIN subquery

I have SQL data that looks like this:
events
id name capacity
1 Cooking 10
2 Swimming 20
3 Archery 15
registrants
id name
1 Jimmy
2 Billy
3 Sally
registrant_event
registrant_id event_id
1 3
2 3
3 2
I would like to select all of the fields in 'events' as well as an additional field that is the number of people who are currently registered for that event. In this case Archery would have 2 registrants, Swimming would have 1, and Cooking would have 0.
I imagine this could be accomplished in a single query but I'm not sure of the correct syntax. How would a query be written to get that data?
SELECT e.*, ISNULL(ec.TotalRegistrants, 0) FROM events e LEFT OUTER JOIN
(
SELECT event_id, Count(registrant_id) AS TotalRegistrants
FROM registrant_event
GROUP BY event_id
) ec ON e.id = ec.event_id
SELECT Events.ID, Events.Name, Events.Capacity,
ISNULL(COUNT(Registrant_Event.Registrant_ID), 0)
FROM Events
LEFT OUTER JOIN Registrant_Event ON Events.ID = Registrant_Event.Event_ID
GROUP BY Events.ID, Events.Name, Events.Capacity
select d.id1, d.name, d.cappacity, count(d.b_id) as number_of_people
from (select eve.id1,eve.name,eve.cappacity,re_eve.b_id
from eve left join re_eve on eve.id1 = re_eve.b_id) d
group by d.id1, d.name, d.cappacity
I tested this in Oracle 11g, and it seems to work
SELECT e.id, e.name, e.capacity, COUNT(re.event_id)
FROM events e
LEFT JOIN registrant_event re
ON e.id = re.event_id
GROUP BY e.id, e.name, e.capacity
select e.id, e.name, e.capacity, IsNull(re.eventCount,0) from events e
left join (
select count(event_id) as eventCount, event_id from registrant_event group by event_id
) re
on e.id = re.event_id
SELECT e.id, count(*) AS NumRegistrants
FROM events e
LEFT JOIN registrant_event re ON re.event_id=e.id
GROUP BY e.id
Note that this will return 1 instead of 0 for events with no registrants. To get it to show 0 instead, you have to get a little more complicated:
SELECT *,
(SELECT COUNT(*) FROM registrant_event WHERE event_id=id) AS NumRegistrants
FROM events
SELECT
events.*
, COUNT(registrant_event.registrant_id) AS registrantsCount
FROM events
LEFT JOIN registrant_event ON events.id = registrant_event.event_id
GROUP BY events.id