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';
Related
I am trying to alias a table in a window function, but not sure what I am doing wrong as when I alias it gives error that the columns cannot be resolved
SELECT e.city,
e.time,
e.day,
e.id,
m.id
FROM
(SELECT *,
rank() OVER (PARTITION BY e.id,
e.bin
ORDER BY e.time ASC) rnk
FROM table e
JOIN table2 m
on m.id = e.id
WHERE e.status = 'YES'
AND e.day BETWEEN date '2019-05-06' and date '2019-05-08')
WHERE rnk = 1
You have used the e alias in the outermost select. However, there is nothing in scope with that alias. The inner from doesn't "reach out" like that (scopes do "reach in" the other way though).
So:
SELECT e.city, e.time, e.day, e.id
FROM (SELECT e.*,
rank() OVER (PARTITION BY e.id, e.bin ORDER BY e.time ASC) as rnk
FROM table e
WHERE e.status = 'YES' AND
e.day BETWEEN date '2019-05-06' and date '2019-05-08'
) e
-------^ here
WHERE rnk = 1
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.
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;
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;
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