如何在SQL中找到第一个正值和第三个连续正值?

时间:2016-06-23 21:41:27

标签: sql-server

我尝试过使用ROW_NUMBER,但还没有得到它。关于实现这一目标的最佳方法的任何想法。

我希望找到:

- What month did they first cash flow.

- What month did they average 3 months cash flow.

示例数据: 办公室,平衡&年月

  ------------------------------
  |  Office | Balance |  YrMo  |
  |   12    |  111    | 201510 |
  |   12    |  222    | 201511 |
  |   12    | -444    | 201512 |
  |   12    | -777    | 201601 |
  |   12    |  555    | 201602 |
  |   12    |  666    | 201603 |
  |   12    | -888    | 201604 |
  |   12    |  777    | 201605 |
  |   40    | -555    | 201510 |
  |   40    | -200    | 201511 |
  |   40    |  0      | 201512 |
  |   40    |  100    | 201601 |
  |   40    | -555    | 201602 |
  |   40    |  666    | 201603 |
  |   40    |  777    | 201604 |
  |   40    |  888    | 201605 |
  |   40    |  999    | 201606 |

第一个正余额将是:

-office 12 , Balance 111 , YrMo 201510
-office 40 , Balance 100 , YrMo 201601

办公室第一个月平均3个正余额:

-office 40 , Balance 999 , YrMo 201606

这是#test表脚本:

IF OBJECT_ID('tempdb..#test') IS NOT NULL
DROP TABLE #test
GO

CREATE TABLE #test (office INT , Balance INT, YrMo INT ) ;

INSERT  INTO #test VALUES  (12 ,  111 , 201510) ;
INSERT  INTO #test VALUES  (12 ,  222 , 201511) ;
INSERT  INTO #test VALUES  (12 , -444 , 201512) ;
INSERT  INTO #test VALUES  (12 , -777 , 201601) ;
INSERT  INTO #test VALUES  (12 ,  555 , 201602) ;
INSERT  INTO #test VALUES  (12 ,  666 , 201603) ;
INSERT  INTO #test VALUES  (12 , -888 , 201604) ;
INSERT  INTO #test VALUES  (12 ,  777 , 201605) ;
INSERT  INTO #test VALUES  (40 , -555 , 201510) ;
INSERT  INTO #test VALUES  (40 , -200 , 201511) ;
INSERT  INTO #test VALUES  (40 ,  0   , 201512) ;
INSERT  INTO #test VALUES  (40 , 100  , 201601) ;
INSERT  INTO #test VALUES  (40 , -555 , 201602) ;
INSERT  INTO #test VALUES  (40 , 666  , 201603) ;
INSERT  INTO #test VALUES  (40,  777  , 201604) ;
INSERT  INTO #test VALUES  (40 , 888  , 201605) ;
INSERT  INTO #test VALUES  (40 , 999  , 201606) ;

提前致谢

2 个答案:

答案 0 :(得分:1)

;with cteFirst as (
    Select *
          ,FirstPos=Row_Number() over (Partition By Office Order By YrMo,Balance) from #Test  Where Balance>0 
),
  cteCons as (
    Select * 
          ,TestCons=Lag(IIf(IIf(sign(balance)=1,1,0)=1,1,0),1,0) over (Partition By Office Order By YrMo)
                   +Lag(IIf(IIf(sign(balance)=1,1,0)=1,1,0),2,0) over (Partition By Office Order By YrMo)
                   +Lag(IIf(IIf(sign(balance)=1,1,0)=1,1,0),3,0) over (Partition By Office Order By YrMo)
    from #Test 
)
Select *,Status='First Positive' from cteFirst where FirstPos=1
Union All
Select *,Status='3 Cons' from cteCons where TestCons=3

返回

office  Balance YrMo    FirstPos    Status
12      111     201510  1           First Positive
40      100     201601  1           First Positive
40      999     201606  3           3 Consequtive

答案 1 :(得分:1)

我又添了一个例子。这个陷阱在日期中存在差距。

  

如果要查看所有标志以及数据如何进展,请删除    - 之前选择*来自cteFinal Order by Office,YrMo

我添加了另一个办公室,其中有3个连续的正余额,但月份不是(没有6月)。通知Office 99无法满足连续月份标准

office  Balance YrMo
99      199     201605
99      299     201607
99      399     201608

更新的查询如下

;with cteBase as (
    Select *
          ,RowNr  = Row_Number() over (Partition By Office Order By Office,YrMo,Balance) 
          ,MthSeq = case when cast(YrMo as int)-Lag(YrMo,1,YrMo-1) over (Partition By Office Order By YrMo) in (1,89) then 1 else 0 end
          ,IsPos  = IIf(Balance>0,1,null)
     from #Test
)
,cteFinal as (
    Select *
          ,PosRowNr = min(RowNr*IsPos) over (Partition By Office Order By RowNr) 
          ,TestCons = MthSeq * (
                      Lag(IIf(IIf(sign(balance)=1,1,0)=1,1,0),1,0) over (Partition By Office Order By YrMo)
                     +Lag(IIf(IIf(sign(balance)=1,1,0)=1,1,0),2,0) over (Partition By Office Order By YrMo)
                     +Lag(IIf(IIf(sign(balance)=1,1,0)=1,1,0),3,0) over (Partition By Office Order By YrMo)
                     )
    From  cteBase
)
--Select * from cteFinal Order by Office,YrMo
Select Office
      ,Balance
      ,YrMo
      ,Status = IIf(RowNr=PosRowNr,'First Positive','')+IIf(TestCons=3,'Consecutive Months','')
 From cteFinal 
 Where TestCons=3 or RowNr=PosRowNr
 Order by Status Desc,Office,YrMo

结果

Office  Balance YrMo    Status
12      111     201510  First Positive
40      100     201601  First Positive
99      199     201605  First Positive
40      999     201606  Consecutive Months