ahem, well, I think that's covered it, thanks very much that's 
excellent. That has to be in the top ten of 'comprehensive replies'

I was with you on the first option. I wanted to avoid dipping into perl 
in this case ( or at least I was trying to get by without it.)

I will go with the second option as there are only 6 members max per 
family so it should handle this efficiently enough.

Thanks again
Rich

Rob wrote:

>I see at least three different techniques, each of which performs better for
>different datasets. First, let's formalize our environment:
>
>create table theTable (family int, member int, score int);
>insert into theTable values (1,1,10), (1,2,15), (1,3,12), (1,4,17);
>insert into theTable values (2,1,5),(2,2,7),(2,3,9),(2,4,10);
>insert into theTable values (3,1,4),(3,2,8),(3,3,2);
>
>You'd like to effectively select values based on top "nth order statistic",
>or the nth biggest number, which is equivalent to MAX() for n==0 (or n==1,
>if you think one-based). Unfortunately, I don't believe MySQL has a general
>"nth order statistic" operation. What's more, you want to join the selected
>order statistic back to its original data row, which MySQL can't do natively
>even with MAX().
>
>The first technique is the one that's been suggested: Run a simply query for
>each family and limit yourself to two results:
>
>select * from theTable where family=1 order by score desc limit 2;
>select * from theTable where family=2 order by score desc limit 2;
>select * from theTable where family=3 order by score desc limit 2;
>
>This is efficient only if you've got a very small number of families and are
>willing to code a loop into your interface language.
>
>Alternatively, you can compute your order statistic explicitly by joining
>the table against itself, and then filter based on that:
>
>select max(curEntry.family) as family,max(curEntry.member) as
>member,max(curEntry.score),count(*) as orderstatistic
>from theTable as curEntry, theTable as greaterEntries
>where curEntry.family = greaterEntries.family and curEntry.score <=
>greaterEntries.score
>group by curEntry.family, curEntry.member
>having orderstatistic < 3
>order by family, orderstatistic;
>
>This manages to pack to whole logic into one query, and is very easy to
>change to compute the top three, top four, etc. with no additional code.
>Unfortunately, MySQL is unlikely to be able to optimize this to look at less
>than the entire table regardless of what indices you provide. (A 'having'
>clause usually implies that this is the case.) If you have a very large
>number of members per family, this is clearly inefficient since you should
>only really need to analyze O(number of families) rows in order to compute
>your result.
>
>Finally, you can use temporary tables to compute intermediary results, with
>each step making use of MAX() in the hope that MySQL is able to optimize
>MAX() by using an index. I'm not sure if MySQL does currently optimize this
>or not (please post the answer, if anyone knows), but it's definitely doable
>in theory if you've got the right indices lying around.
>The SQL here would be along the lines of:
>
>create temporary table topScores
>select max(family) as family, max(score) as score
>from theTable
>group by theTable.family;
>
>create temporary table topMembers
>select max(theTable.family) as family,
>max(theTable.member) as member,
>max(theTable.score) as score
>from theTable, topScores
>where theTable.family = topScores.family
>and theTable.score = topScores.score
>group by theTable.family;
>
>create temporary table sndScores
>select max(theTable.family) as family,
>max(theTable.score) as score
>from theTable,topMembers
>where theTable.family = topMembers.family
>and theTable.member != topMembers.member
>group by theTable.family;
>
>create temporary table sndMembers
>select max(theTable.family) as family,
>max(theTable.member) as member,
>max(theTable.score) as score
>from theTable,sndScores,topMembers
>where theTable.family = sndScores.family
>and theTable.score = sndScores.score
>and sndScores.family = topMembers.family
>and theTable.member != topMembers.member
>group by theTable.family;
>
>insert into topMembers select * from sndMembers;
>
>select * from topMembers order by family,score DESC;
>
>drop table sndMembers;
>drop table sndScores;
>drop table topMembers;
>drop table topScores;
>
>The last temporary table, at the least, can be turned into a simple insert
>in our limited example, but I've provided it as a distinct table for
>clarity. This technique is certainly much more complex, but for very large
>numbers of members per family it might be more efficient, and it still
>requires no logic in the interface language: there is only one command which
>returns a result set for processing, and that is the final result. This 
>approach does require additional logic to extend to more than the top two
>scores, which requires another pair of SQL statements per result. If you are
>looking for order statistics on the order of the average number of members
>per family, then the single-statement approach will almost certainly be a
>better choice.
>
>-Rob
>
>(because I'm bored at work, that's why...)
>
>On 22/5/02 at 10:36 am, R.Dobson <[EMAIL PROTECTED]> wrote:
>
>>Hi,
>>thanks for all of the replies to my query.
>>I'm not sure that I explained my problem very well as the solutions 
>>received are solutions to the problem I described, but not the one I 
>>meant :-)  (I don't think anyway)
>>
>>
>>I have a table in the format:
>>
>>family | member | score
>>--------------------------------
>>1          |       1      |    10
>>1          |       2      |    15
>>1          |       3      |    12
>>1          |       4      |    17
>>2          |       1      |     5
>>2          |       2      |     7
>>2          |       3      |     9
>>2          |       4      |    10
>>3          |       1      |     4
>>3          |       2      |     8
>>3          |       3      |     2
>>
>>I want the top 2 highest scorers for each family as in:
>>
>>family | member | score
>>-------------------------------
>>1          |     4        |    17
>>1          |     2        |    15
>>2          |     4        |    10
>>2          |     3        |     9
>>3          |     2        |     8
>>3          |     1        |     4
>>
>>
>>Thanks again,
>>Rich
>>
>>mysql
>>
>
>




---------------------------------------------------------------------
Before posting, please check:
   http://www.mysql.com/manual.php   (the manual)
   http://lists.mysql.com/           (the list archive)

To request this thread, e-mail <[EMAIL PROTECTED]>
To unsubscribe, e-mail <[EMAIL PROTECTED]>
Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php

Reply via email to