Author |
Topic |
Rauken
Posting Yak Master
108 Posts |
Posted - 2002-10-16 : 08:50:56
|
I have a table called result, it looks like this:ResultId INTPersonId INTResultDate DATETIMERaceNo INTRaceLenght INTRaceTime DECThe table is filled with result for runners, each runner can have 3-10 results. Today the table consist of What I want to do is get the average of three lowest times for each runner. I've been back and forth with this, it seems like it should be an easy task with a select statement or two but I'm going nuts! |
|
mr_mist
Grunnio
1870 Posts |
Posted - 2002-10-16 : 08:56:40
|
I'm not sure it is that easy to be honest. Anyway you need to specify if you want any 3 lowest times for a runner, or the three lowest times for a runner in a certain race no/ race length. |
 |
|
Page47
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2002-10-16 : 09:01:26
|
This is actually a pretty tricky query to wrap your head around.Without actual DDL and sample data, I am unable to test this query, but I think this should do it for you ...select PersonId, avg(RaceTime) as 'avg worse 3 times'from dbo.results rwhere exists ( select 1 from dbo.results where personid = r.personid and racetime = r.racetime group by someid having ( select count(*) from dbo.results where personid = r.personid and racetime > r.racetime ) < 3 )order by personid Jay White{0} |
 |
|
Rauken
Posting Yak Master
108 Posts |
Posted - 2002-10-16 : 09:03:39
|
Thanks for the query, I'll try it out. It's just the average of the three lowest times for each person, not any specific race. |
 |
|
Rauken
Posting Yak Master
108 Posts |
Posted - 2002-10-16 : 09:18:50
|
Ok I get the following result:Column 'r.personid' is invalid in the select list because it is not contained in an aggregate function.... |
 |
|
Merkin
Funky Drop Bear Fearing SQL Dude!
4970 Posts |
Posted - 2002-10-16 : 09:31:10
|
which it is why Page47 subtly suggested you provide enough info for him to test the query. We can't mind read, so you might have to do some debugging now Damian |
 |
|
Rauken
Posting Yak Master
108 Posts |
Posted - 2002-10-16 : 09:34:30
|
hehe ok I understand :-) |
 |
|
Page47
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2002-10-16 : 09:47:50
|
select PersonId, avg(RaceTime) as 'avg worse 3 times'from dbo.results rwhere exists ( select 1 from dbo.results where personid = r.personid and racetime = r.racetime group by personid having ( select count(*) from dbo.results where personid = r.personid and racetime > r.racetime ) < 3 )order by personid Sorry ...Jay White{0} |
 |
|
byrmol
Shed Building SQL Farmer
1591 Posts |
Posted - 2002-10-16 : 09:52:23
|
SELECT PersonID, AVG(RaceLength) as LowAverageFROM Result RWHERE EXISTS (SELECT 1 FROM Result WHERE RaceLength <= R.RaceLengthGROUP BY PersonID HAVING COUNT(Race) <= 3)GROUP BY PersonID DavidM"SQL-3 is an abomination.."Edited by - byrmol on 10/16/2002 09:53:22 |
 |
|
Page47
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2002-10-16 : 10:12:32
|
GOTO EDIT:First off, I think you meantSELECT PersonID, AVG(RaceLengthRaceTime) as LowAverageFROM Result RWHERE EXISTS (SELECT 1 FROM Result WHERE RaceLengthRaceTime <=>= RaceLengthRaceTimeGROUP BY PersonID HAVING COUNT(RaceRaceTime) <= 3)GROUP BY PersonID Second, looking at the execution plans and considering no indexes (again without DDL ....) it seems as though my original query is presenting a better subtree cost (0.118 vs 0.190). Your grouping in the exists is not filtered, so the sort operation is much more costly(54% or query cost). As the number of rows in the table increase, I think you'll find my query performing better and better ... EDIT: actually, on second look, you query won't work. It will return the same average for all the racers ... the average of the three worst times across all racers ... you need to correlate the subquery on PersonID to get only those races for that person ...Jay White{0}Edited by - Page47 on 10/16/2002 10:31:48 |
 |
|
Arnold Fribble
Yak-finder General
1961 Posts |
Posted - 2002-10-16 : 11:31:33
|
Surely it should be grouped on both PersonId and RaceLength -- you wouldn't want to average someone's 200 metre time with their 100 metre time! |
 |
|
mr_mist
Grunnio
1870 Posts |
Posted - 2002-10-16 : 11:40:40
|
quote: Surely it should be grouped on both PersonId and RaceLength -- you wouldn't want to average someone's 200 metre time with their 100 metre time!
I must admit I find that somewhat odd too. But he did say "It's just the average of the three lowest times for each person"... |
 |
|
Rauken
Posting Yak Master
108 Posts |
Posted - 2002-10-17 : 11:24:01
|
I'm from Sweden so my English might not be the best at all times. What I mean is the average of the three best times (lowest?). Thanks for all the help! |
 |
|
mr_mist
Grunnio
1870 Posts |
Posted - 2002-10-18 : 03:37:32
|
Ahh, you want the average three *fastest* times. In which case you'd probably have to switch around the > symbol in Page47's query. Or something. |
 |
|
sanjnep
Posting Yak Master
191 Posts |
Posted - 2002-10-18 : 06:05:51
|
"Heaven's light is our guide"Sanjeevshrestha |
 |
|
mr_mist
Grunnio
1870 Posts |
Posted - 2002-10-18 : 06:18:06
|
quote: "Heaven's light is our guide"
That's as maybe, but how does your resume answer the question? |
 |
|
Page47
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2002-10-18 : 06:47:37
|
quote: Ahh, you want the average three *fastest* times. In which case you'd probably have to switch around the > symbol in Page47's query. Or something.
Correct ..select PersonId, avg(RaceTime) as 'avg worsebest 3 times'from dbo.results rwhere exists ( select 1 from dbo.results where personid = r.personid and racetime = r.racetime group by personid having ( select count(*) from dbo.results where personid = r.personid and racetime < r.racetime ) < 3 )order by personid Jay White{0}Edited by - Page47 on 10/18/2002 07:57:04 |
 |
|
ValterBorges
Master Smack Fu Yak Hacker
1429 Posts |
Posted - 2002-10-18 : 18:21:11
|
Page47 nice solution!Just one question is it missing a group by clause since you are using the avg aggregate function????Group By PersonID |
 |
|
nivaskhan
Starting Member
17 Posts |
Posted - 2002-10-23 : 08:20:04
|
Nice solution...But i cant understand what it does.Figuring it out how the results output.Can youplease be a little bit brief how each inner query works and whats its output.That will of great help.Thanks in advance---------------------------SELECT PERSONID, AVG(RACETIME) AS [AVG WORSEBEST 3 TIMES]FROM DBO.RESULTS RWHERE EXISTS ( SELECT 1 FROM DBO.RESULTS WHERE PERSONID = R.PERSONID AND RACETIME = R.RACETIME GROUP BY PERSONID HAVING ( SELECT COUNT(*) FROM DBO.RESULTS WHERE PERSONID = R.PERSONID AND RACETIME < R.RACETIME ) < 3 )GROUP BY PERSONIDORDER BY PERSONIDRegards,Nivas |
 |
|
Page47
Master Smack Fu Yak Hacker
2878 Posts |
Posted - 2002-10-23 : 08:47:01
|
quote: Page47 nice solution! Just one question is it missing a group by clause since you are using the avg aggregate function???? Group By PersonID
You are correct. My bad. Again, I stress that without DDL and sample data I am unable to test this query ....quote: Can youplease be a little bit brief how each inner query works
Hum...Typically, complicated set-based constructs are difficult to express in words ... basically, the correlated sub-query will return 1 for a given row if and only if there are less than three other rows in the table for the same person which have greater times.Jay White{0} |
 |
|
Rauken
Posting Yak Master
108 Posts |
Posted - 2002-10-23 : 08:56:29
|
Hi again! Thanks for all help on this problem. Yes there is a group clause missing here is the correct solution: select PersonId, avg(RaceTime) as 'avg worsebest 3 times'from dbo.results rwhere exists ( select 1 from dbo.results where personid = r.personid and racetime = r.racetime group by personid having ( select count(*) from dbo.results where personid = r.personid and racetime < r.racetime ) < 3 )group by personidorder by personid |
 |
|
Next Page
|