1. 程式人生 > >排名趨勢公式

排名趨勢公式

set arr obj 趨勢 ins left 結合 eat 能夠

開始

這裏有個連續幾個月的個人銷售數據,如:

技術分享

圖1.

要求對個人銷量按月進行排名,還能夠描述出一個人在連續幾個月的排名趨勢,是上升還是下降,連續上升多少個月,連續下降多少個月,如圖2.

技術分享

圖2.

分析

由於要描述連續升和連續降的特點,每月的連續升降,需要參考本月之前的排名情況,所以最好是通過實體表來存儲每月的排名數據。如圖3.

技術分享

圖3.

在 圖3,中,有一個字段RankTrend描述排名趨勢,正數(+n)表示上升,負數(-n)表示下降,0表示第一次排名或名次不變。

場景1:第一次排名從0開始計數,下個月名次上升的情況,RankTrend +=1, 反之,名次出現下降 ,RankTrend -=1 。

技術分享

圖4.

Kent 在1月份第一次加入排名,1月排名趨勢為0;2月份,名次從第4名升到第2名,屬於上升趨勢,那麽RankTrend +=1; 3月也是一樣,從2月的第2名升到第1名,那麽RankTrend +=1;

技術分享

圖5.

John 在1月份第一次加入排名,1月排名趨勢為0;2月份,名次從第1名降到第5名,屬於下降趨勢,那麽RankTrend -=1; 3月也是一樣,從2月的第5名降到第6名,那麽RankTrend -=1;

場景2:上個月的排名趨勢是上升的,即RankTrend = (+n), 本月排名突然下降,那麽RankTrend = (-1),這裏不能直接RankTrend -=1,因為直接減1不能體現連續升降趨勢。

技術分享

圖6.

分析方法如前面(略.)

場景3:上個月的排名趨勢是下降的,即RankTrend = (-n), 本月排名突然下降,那麽RankTrend = (+1),這裏不能直接RankTrend +=1,因為直接加1不能體現連續升降趨勢。

技術分享

圖7.

分析方法如前面(略.)

排名趨勢公式

根據前面的分析,我們涉及到一些數值,(+n),(-n) ,-1 , 1 , 0 。結合這些數,我們可以通過一個簡單的數字組合和位運算,整理得出一個排名趨勢公式:

【排名趨勢】 = isnull( sign( [上月名次] - [本月名次] ) + [上月排名趨勢值] x ( 1 - abs(sign( sign([上月名次] - [本月名次]) XOR sign([上月排名趨勢值]) )) ) ,0)

[註明]:

  • isnull()函數是判斷Null的時候取0
  • sign() 函數是正負函數,返回-1,0,1
  • abs() 函數是取絕對值
  • XOR 表示異或運算

具體可以自己去拆分,這裏暫時不詳解。

測試例子

1.建表和Insert 測試數據

use tempdb
go
if object_id(PersonalSalesRank) Is not null drop Table PersonalSalesRank
go
create table PersonalSalesRank(Name nvarchar(20),YM date, SalesQty int ,RankNr int,RankTrend int)
go
set nocount on
insert into dbo.PersonalSalesRank ( Name , YM , SalesQty  )
    values    
--2017-01
    (Kent,20170101,400),
    (John,20170101,758),
    (Rob,20170101,365),
    (Ruben,20170101,487),
    (Andy,20170101,651),
--2017-02
    (Andy,20170201,668),
    (Christy,20170201,541),
    (Kent,20170201,712),
    (Ruben,20170201,729),
    (Rob,20170201,365),
    (John,20170201,465),
--2017-03
    (Andy,20170301,651),
    (Christy,20170301,588),
    (Kent,20170301,769),
    (Ruben,20170301,752),
    (Rob,20170301,552),
    (John,20170301,421)

go

2.創建排名趨勢函數

if object_id(fn_RankTrend) Is not null drop function  fn_RankTrend
go
/********************************************************************************************
%% Program Name    :fn_RankTrend
%% Author        : Andy.Wei
%% Description    :
%% InParameter    :
%% OutParameter    :
%% Created Date    : 2017-05-12
%% Revision History :
%% Modified Date Modified By  version Description
%%
********************************************************************************************/
create function fn_RankTrend
(
    @CurrentRankNr int,
    @LastRankNr int,
    @LastRankTrend int
)
returns int 
as
begin

    return(isnull(sign( @LastRankNr - @CurrentRankNr) + @LastRankTrend * ( 1 - abs(sign( sign(@LastRankNr - @CurrentRankNr)^sign(@LastRankTrend) )) ) ,0))
end
go

3. 計算排名

--排名
;with cte_Rank as 
(
    select  RankNr,dense_rank() over(partition by YM order by SalesQty desc) as RankNr_1 from dbo.PersonalSalesRank
)
update a  
    set a.RankNr=a.RankNr_1
    from cte_Rank a

4. 計算排名趨勢

--更新排名趨勢
declare @YM date=20170101
while(1=1)
begin
    update a 
        set a.RankTrend=dbo.fn_RankTrend(a.RankNr,b.RankNr,b.RankTrend)
        from dbo.PersonalSalesRank a 
            left join dbo.PersonalSalesRank b on b.Name=a.Name
                and b.YM=dateadd(month,-1,@YM)
        where a.YM=@YM;
    if @@ROWCOUNT =0 break;
    print @YM
    set @YM=dateadd(month,1,@YM)
end

5. 測試

select    name as [姓名],
        convert(char(7),a.YM,121) as [月份],
        a.SalesQty as [銷量],
        convert(nvarchar(20),N+rtrim(a.RankNr)+N) as [排名],
        case sign(a.RankTrend)
            when -1 then N
            when 1  then N
            else N‘‘
        end as [排名升降],
        case 
            when a.RankTrend>=2 then N連續+rtrim(abs(a.RankTrend))+N
            else N‘‘
        end as [連續上升],
        case 
            when a.RankTrend<=-2 then N連續+rtrim(abs(a.RankTrend))+N
            else N‘‘
        end as [連續下降]
    from dbo.PersonalSalesRank a 
    order by 2,3 desc
go

技術分享

最後

這只是一個簡單的例子,但可以從簡單的例子發現一些事物的某種共性,由此可以明白它可以應用於相識而不同的各種應用案例中。

排名趨勢公式