create table if not exists bookings (
bk_id integer auto_increment primary key ,
bk_date datetime ,
bk_quantity integer ,
bk_amount decimal(19,4) ,
bk_salesperson varchar(50) ,
bk_customer varchar(10)
)
;
insert into bookings( bk_date, bk_quantity, bk_amount, bk_salesperson, bk_customer )
select '20090928', 3, 56.0960, 'mark_wills', 'C543423'
union all select '20091003', 9, 220.8000, 'mwvisa1', 'C1234318'
union all select '20091008', 14, 364.4800, 'chapmandew', 'C89086'
union all select '20090928', 18, 627.6896, 'chapmandew', 'C101160'
union all select '20091002', 23, 790.2400, 'aneeshattingal', 'C123796'
union all select '20090930', 120, 4187.6480, 'angeliii', 'C123419'
union all select '20091010', 11, 276.0000, 'mwvisa1', 'C1234595'
union all select '20091007', 23, 784.6120, 'chapmandew', 'C1011923'
union all select '20091007', 8, 187.6480, 'angeliii', 'C123275'
union all select '20090910', 36, 1234.5000, 'aneeshattingal', 'C1234465'
union all select '20090912', 353, 12345.0000, 'angeliii', 'C1234300'
union all select '20090917', 163, 5690.5000, 'chapmandew', 'C543497'
union all select '20090909', 4, 87.6500, 'mark_wills', 'C543937'
union all select '20090914', 9, 234.7500, 'aneeshattingal', 'C123206'
union all select '20090908', 3, 69.5000, 'chapmandew', 'C890141'
union all select '20090913', 5, 123.4563, 'mark_wills', 'C101132'
union all select '20090917', 84, 2931.2500, 'angeliii', 'C1234754'
union all select '20090914', 5, 109.5625, 'angeliii', 'C543382'
union all select '20090915', 21, 711.8750, 'chapmandew', 'C890979'
union all select '20090923', 12, 300.1600, 'aneeshattingal', 'C12319'
union all select '20090923', 12, 300.1600, 'aneeshattingal', 'C123481'
union all select '20090924', 56, 1929.0000, 'angeliii', 'C104742'
union all select '20090916', 240, 8375.2960, 'angeliii', 'C123646'
;
select bks.*
from (
select bk_salesperson as salesperson,
bk_customer as customer,
bk_amount as sales,
bk_quantity as units,
(select count(*) from bookings b2
where b2.bk_salesperson = b1.bk_salesperson
and (b2.bk_amount > b1.bk_amount
or (b2.bk_amount = b1.bk_amount
and (b2.bk_quantity > b1.bk_quantity
or (b2.bk_quantity = b1.bk_quantity
and b2.bk_date > b1.bk_date)
)
))
) + 1 as ranking
from bookings b1
) bks
where ranking <= 10
order by salesperson, ranking
;
All execute the above SQL the same and have results that look similar to the below captured from MySQL Query Browser.
OVER ( [ PARTITION BY value_expression , ... [ n ] ]
<ORDER BY_Clause> )
Where PARTITION BY establishes the grouping over which the ranking window functions will count; the ORDER BY, the order of the count.
with bks_ranked
as
(
select bk_salesperson as salesperson,
bk_customer as customer,
bk_amount as sales,
bk_quantity as units,
row_number()
over (partition by bk_salesperson
order by bk_amount desc,
bk_quantity desc,
bk_date desc) ranking
from bookings
)
select *
from bks_ranked
where ranking <= 10
order by salesperson, ranking
;
Runs the same in both MS SQL and Oracle, but look at the results from Oracle.
rank()
over (partition by bk_salesperson
order by bk_amount desc,
bk_quantity desc,
bk_customer) ranking
dense_rank()
over (partition by bk_salesperson
order by bk_amount desc,
bk_quantity desc,
bk_customer) ranking
ntile(10)
over (partition by bk_salesperson
order by bk_amount desc,
bk_quantity desc,
bk_customer) ranking
This would be nice for top 10% of customers by then selecting only customers with ranking = 1. Just for a comparison / visual, take a look at the results.
SELECT bks.*
FROM (
SELECT bk_salesperson AS salesperson,
bk_customer AS customer,
bk_amount AS sales,
bk_quantity AS units,
dcount("*","bookings",
"bk_salesperson = """ &
b1.bk_salesperson & """ and bk_amount > " &
b1.bk_amount)+1 AS ranking
FROM bookings AS b1
) AS bks
WHERE ranking<=10
ORDER BY salesperson, ranking
;
As you can see how this could get cumbersome with just the one criteria of our row numbering included and a quick look through the results will show what "dense ranking" means to you.
select bk_salesperson as salesperson,
group_concat(bk_customer
order by bk_amount desc,
bk_quantity desc,
bk_date desc) as customers
from bookings
group by bk_salesperson
;
And visually resulting in:
select bk_salesperson as salesperson,
bk_customer as customer,
bk_amount as sales,
bk_quantity as units,
find_in_set(b.bk_customer, customers) as ranking
from bookings b
inner join (
select bk_salesperson as salesperson,
group_concat(bk_customer
order by bk_amount desc,
bk_quantity desc,
bk_date desc) as customers
from bookings
group by bk_salesperson
) p on p.salesperson = b.bk_salesperson
where find_in_set(b.bk_customer, customers) <= 10
order by salesperson, ranking
;
VoilĂ !
(select @rownum:=0, @lastsalesperson:=null) r
The idea is exactly as discussed in the link, we have to order our records exactly as needed and then number each sequentially, resetting the count when the new salesperson value is not equal to the last.
select salesperson, customer, sales, units, ranking
from (
select bk_customer as customer,
bk_amount as sales,
bk_quantity as units,
/* if salesperson is same as row above,
increment row number; else, start at 1. */
if(bk_salesperson = @lastsalesperson,
@rownum:=@rownum+1,
@rownum:=1) as ranking,
/* since using @lastsalesperson in @rownum,
have to set @lastsalesperson 2nd;
otherwise, current and last would always equal.
*/
@lastsalesperson:=bk_salesperson as salesperson
from bookings b,
(select @rownum:=0, @lastsalesperson:=null) r
order by bk_salesperson,
bk_amount desc,
bk_quantity desc,
bk_date desc
) bks
where ranking <= 10
order by salesperson, ranking
;
Not too difficult and code should speak for itself, but please leave me comments below for more questions.
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (14)
Author
Commented:Thank you for the kind words and the vote.
Respectfully yours,
Kevin
Author
Commented:Dlookup and the Domain Functions
https://www.experts-exchange.com/A_12.html
Access Techniques: Fast Table Lookup Functions
https://www.experts-exchange.com/A_1921.html
Access & VB's Missing Domain Lookup Functions
https://www.experts-exchange.com/A_2011.html
Additionally, to further stimulate your brain cells and see Dlookup() in action, see:
Computing row-wise aggregations in Access
https://www.experts-exchange.com/A_1775.html
Probably some other very good ones about you can find, just wanted to add these for your convenience.
Thanks again for reading and for the support from those who have/will vote this helpful.
Respectfully yours,
Kevin
Commented:
Author
Commented:Commented:
View More