sql - How to select the TOP 1 record per group (Partition) -


i've got table called tblroutes holds unique list of , routes (f = from; t = to):

| fcity  | fstate | tcity  | tstate | |========|========|========|========| |new york|   ny   | miami  |   ca   | |houston |   tx   |new york|   ny   | ... 

and have table called tblcarrierrates lists bunch of tiers , rates offered carriers travelling routes:

| fcity  | fstate | tcity  | tstate | tier | rate | carrid |  carrname   | |========|========|========|========|======|======|========|=============| |new york|   ny   | miami  |   ca   |   2  | $2.99|  abcd  | abracadabra | |new york|   ny   | miami  |   ca   |   1  | $3.00|  bump  | bumpy rides | |houston |   tx   |new york|   ny   |   2  | $4.00|  slow  |slow carriers| |houston |   tx   |new york|   ny   |   2  | $4.01|  abcd  | abracadabra | ... 

for each unique route listed in tblroutes i'm looking 1 "best" offered tblcarrierrates.

the criteria "the best" lowest tier, followed lowest rate.

the result needs return fields shown in tblcarrierrates, based on 2 routes shown above in tblroutes, desired result be:

| fcity  | fstate | tcity  | tstate | tier | rate | carrid |  carrname   | |========|========|========|========|======|======|========|=============| |new york|   ny   | miami  |   ca   |   1  | $3.00|  bump  | bumpy rides | |houston |   tx   |new york|   ny   |   2  | $4.00|  slow  |slow carriers| 

the approach looking @ sort in ascending order tier , rate, how match top 1 record each unique combination of fcity, fstate, tcity, , tstate:

select a.fcity, a.fstate, a.tcity, a.tstate, q.tier, q.rate, q.carrid, q.carrname tblroutes left join      (select top 1 b.carrid, b.carrname, b.fcity, b.fstate, b.tcity, b.tstate, b.rate, b.tier     tblcarrierrates b     order tblcarrierrates.tier asc, tblcarrierrates.rate asc) q on (a.tstate = q.tstate) , (a.tcity = q.tcity) , (a.fstate = q.fstate) , (a.fcity = q.fcity); 

the query doesn't fail, can guess, subquery i've written (q) returns single record rather 1 each route in tblroutes, end result is:

| fcity  | fstate | tcity  | tstate | tier | rate | carrid |  carrname   | |========|========|========|========|======|======|========|=============| |new york|   ny   | miami  |   ca   |   1  | $3.00|  bump  | bumpy rides | |houston |   tx   |new york|   ny   |      |      |        |             | 

...as can see, nothing's been matched houston new york because sub query returned 1 result rather 1 each route.

how can achieve result i'm after?

i believe looking equivalent of sql server , oracle analytic / windowing functions row_number() on (partition .. order by), e.g. like so.

although isn't directly offered in ms access, believe possible simulate row numbering function in ms access applying correlated subquery counts number of rows have same "partition" (as defined join filter), , in each row ranked counting number of preceding rows in same partition, 'below' ordering criteria:

select a.fcity, a.fstate, a.tcity, a.tstate, q.tier, q.rate, q.carrid, q.carrname, therank tblroutes left join      (       select b.carrid, b.carrname, b.fcity, b.fstate, b.tcity, b.tstate, b.rate, b.tier,        (         select count(*) + 1          tblcarrierrates rnk          -- partition simulation (join)         b.fcity = rnk.fcity , b.fstate = rnk.fstate                , b.tcity = rnk.tcity , b.tstate = rnk.tstate                -- order simulation               , (rnk.tier < b.tier or                   (rnk.tier = b.tier , rnk.rate < b.rate))) therank       tblcarrierrates b) q on (a.tstate = q.tstate) , (a.tcity = q.tcity)      , (a.fstate = q.fstate) , (a.fcity = q.fcity) -- now, want top rank in each partition. therank = 1; 

just forewarned of performance - subquery executed each row. also, if there ties, both rows returned.

the +1 start each partition off row number of 1 (since there 0 preceding rows in partition)

edit, taking out comments

select a.fcity, a.fstate, a.tcity, a.tstate, q.tier, q.rate, q.carrid, q.carrname, therank tblroutes left join      (       select b.carrid, b.carrname, b.fcity, b.fstate, b.tcity, b.tstate, b.rate, b.tier,        (         select count(*) + 1          tblcarrierrates rnk          b.fcity = rnk.fcity , b.fstate = rnk.fstate                , b.tcity = rnk.tcity , b.tstate = rnk.tstate                , (rnk.tier < b.tier or                   (rnk.tier = b.tier , rnk.rate < b.rate))) therank       tblcarrierrates b) q on (a.tstate = q.tstate) , (a.tcity = q.tcity)      , (a.fstate = q.fstate) , (a.fcity = q.fcity) therank = 1 

Comments

Popular posts from this blog

c++ - Difference between pre and post decrement in recursive function argument -

php - Nothing but 'run(); ' when browsing to my local project, how do I fix this? -

php - How can I echo out this array? -