Find average score from event at specific meeting - sql

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;

Related

SQL Finding Group where attendance less than average

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;

Find lowest number from column in table

I have 3 tables - EVENT, MEMBER, RANK. I need to show the best result (from RANK) along with the member it belongs to, for a specific event (ex EVENT01) What is the simplest way to do this? My code below seems to select the lowest number, but duplicates itself and claims other members got the same result.
Expected output:
EVENT_ID EVENT_TYPE EVENT_NAME MEMBER_ID MEMBER_NAME RESULT
event01 swimming 100m mem001 John Smith 10
Code so far:
SELECT E.EVENT_ID, E.EVENT_TYPE, E.EVENT_NAME, R.MEMBER_ID, M.MEMBER_FIRSTNAME, M.MEMBER_LASTNAME, (SELECT MIN(RESULT)
FROM RANK WHERE E.EVENT_ID = 'EVENT003' ) AS AVG_INCOME_ALL_CLUBS
FROM EVENT E, RANK R, MEMBER M
WHERE E.EVENT_ID = R.EVENT_ID
AND R.MEMBER_ID = M.MEMBER_ID
ORDER BY MEMBER_ID;
First, learn to use explicit JOIN syntax.
Second, the answer to your question is ROW_NUMBER():
SELECT *
FROM (SELECT E.EVENT_ID, E.EVENT_TYPE, E.EVENT_NAME, R.MEMBER_ID, M.MEMBER_FIRSTNAME, M.MEMBER_LASTNAME,
ROW_NUMBER() OVER (PARTITION BY E.EVENT_ID ORDER BY R.RESULT ASC) as SEQNUM
FROM EVENT E, JOIN
RANK R
ON E.EVENT_ID = R.EVENT_ID JOIN
MEMBER M
ON R.MEMBER_ID = M.MEMBER_ID
) ERM
WHERE SEQNUM = 1
ORDER BY MEMBER_ID;
SELECT E.EVENT_ID, E.EVENT_TYPE, E.EVENT_NAME, R.MEMBER_ID,M.MEMBER_FIRSTNAME, M.MEMBER_LASTNAME,
FROM EVENT E, JOIN
RANK R
ON E.EVENT_ID = R.EVENT_ID JOIN
MEMBER M
ON R.MEMBER_ID = M.MEMBER_ID
where R.RESULT=
(SELECT MIN(RESULT) FROM RANK WHERE E.EVENT_ID = 'EVENT003') AND R.EVENT_ID='EVENT003';

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.

Select lowest value and return first row only

I am having difficulty returning the first row only from the following query. I am trying to return the lowest value in the RESULT column for a particular EVENT which works fine but it also returns other rows, I just want the one. What is the best way to achieve this?
SELECT E.EVENT_ID, E.EVENT_TYPE, E.EVENT_NAME, M.MEMBER_ID, M.MEMBER_FIRSTNAME, M.MEMBER_LASTNAME, (SELECT MIN(RESULT)
FROM RANK)
FROM EVENT E JOIN
RANK R
ON E.EVENT_ID = R.EVENT_ID JOIN
MEMBER M
ON M.MEMBER_ID = R.MEMBER_ID
WHERE E.EVENT_ID = 'EVENT001'
ORDER BY RESULT;
The subquery in the solution below is copied and pasted from your original post, I didn't test it (obviously since I didn't have your tables), EXCEPT for the extra field: ROW_NUMBER() OVER .... instead of the MIN(RESULT...)
This assigns a row in each "partition" using the ordering indicated (notice DESC), and in the outer query you select the rows where this row_number equals 1.
SELECT EVENT_ID, EVENT_TYPE, EVENT_NAME, MEMBER_ID,
MEMBER_FIRSTNAME, MEMBER_LASTNAME, RESULT
FROM
(
SELECT E.EVENT_ID, E.EVENT_TYPE, E.EVENT_NAME,
M.MEMBER_ID, M.MEMBER_FIRSTNAME, M.MEMBER_LASTNAME,
R.RESULT,
row_number() over (partition by e.event_id order by r.result) as rn
FROM EVENT E JOIN
RANK R
ON E.EVENT_ID = R.EVENT_ID JOIN
MEMBER M
ON M.MEMBER_ID = R.MEMBER_ID
WHERE E.EVENT_ID = 'EVENT001'
)
WHERE RN = 1;
This assumes you want to return only one row, even if there is a tie for the lowest score. If there are ties, which row will be selected is undetermined (at least with this solution; you could add more clauses in ORDER BY). If in the case of ties you want ALL tied members to be listed, then you can use DENSE_RANK() instead of ROW_NUMBER().
So along with the row's result you want to show the event's minimum result. Use MIN OVER for this:
select
e.event_id,
e.event_type,
e.event_name,
m.member_id,
m.member_firstname,
m.member_lastname,
r.result,
min(r.result) over () as min_result
from event e
join rank r on e.event_id = r.event_id
join member m on m.member_id = r.member_id
where e.event_id = 'EVENT001'
order by r.result;

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