Select lowest number from column and show other columns - sql

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.

Related

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 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;

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;

Writing a query to find MAX number in Oracle SQL

I am suppose to Write a query that will display the largest number of movies rented by one member and that member's name. Give the output column a meaningful name such as MAXIMUM NUMBER.
This is what I have.
select max(maximum_movies)
from (select count(*)maximum_movies
from mm_member join mm_rental on
mm_rental.member_id = mm_member.member_id
group by first, last);
I got the maximum number but the output should be like this.
First Last Maximum_movies
John Doe 4
But the output is
Maximum_movies
4
Any suggestions?
You could use analytic rank this way. Demo on Fiddle
select memberid,
last,
first,
rental_count
from (
select m.mm_memberid memberid,
m.mm_last last,
m.mm_first first,
count(*) rental_count,
rank() over (order by count(*) desc ) as count_ranking
from mm_member m
inner join mm_rental r on m.mm_memberid=r.mm_memberid
group by m.mm_memberid,
m.mm_last,
m.mm_first
)
where count_ranking=1
Something like this:
WITH CTE_CNT AS (
SELECT first, last, COUNT(*) num
FROM
mm_member
JOIN mm_rental ON mm_rental.member_id = mm_member.member_id
GROUP BY first, last
),
SELECT cnt.first, cnt.last, maxrent.mx
FROM (
SELECT MAX(num) as mx FROM CTE_CNT
) maxrent JOIN CTE_CNT AS cnt ON cnt.num = maxrent.mx
;
use this :
select first,last, maximum_movies
from mm_member join mm_rental on
mm_rental.member_id = mm_member.member_id group by first, last where
maximum_movies = (select max(maximum_movies) from (select count(*)maximum_movies
from mm_member join mm_rental on
mm_rental.member_id = mm_member.member_id group by first, last));
You can do the select in only 1 step. It is not really a MAX you are looking for, just a COUNT of the joined table.
SELECT TOP 1
M.member_id
, M.first
, M.last
, COUNT(R.*) MovieCount
FROM mm_member M
JOIN mm_rental R ON R.member_id = M.member_id
GROUP BY M.member_id, M.first, M.last
ORDER BY MovieCount DESC

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