如何查询V形数据?

时间:2018-06-20 07:52:25

标签: sql sql-server sql-server-2008

TxnID    RunningAmount    MemberID
==================================
1        80000            20
2        90000            20
3        70000            20  //<==== Falls but previously never below 100k, hence ignore
4        90000            20
5        110000           20  
6        60000            20  //<==== Falls below 100k, hence we want ID 8
7        80000            20
8        120000           20
9        85000            28
...
....

如何构造查询以使其按成员分组,获取形成“ V”形的第一个transactionID。即使是伪代码也很好,我也无法分享我的尝试,因为我对如何做到完全一无所知。

更新

很抱歉,没有对条件的解释。我们寻找的基本金额为100k。 ID是随机的,肯定需要行号

  1. 我们忽略ID = 5之前的所有交易,因为它们的runningAmount从未超过100k。

  2. 现在,当ID=5超过10万时,我们检查ID=5之后的交易是否runningAmount中的下降趋势低于10万。

  3. 我们立即看到ID=6降至10万以下,因此我们希望找到再次超过10万(如果有)的第一笔交易。

从上面的数据样本中,预期结果仅为一条记录,即ID=8

对于每个成员,根据我提到的条件,只会找到一个或零个记录

2 个答案:

答案 0 :(得分:1)

尝试此查询:

declare @tbl table(TxnID int, RunningAmount int, MemberID int);
insert into @tbl values 
(1, 80000, 20),
(2, 90000, 20),
(3, 70000, 20),
(4, 90000, 20),
(5, 110000, 20),
(6, 60000, 20),
(7, 120000, 20),
(8, 85000, 28);

select TxnID, RunningAmount, MemberID,
       LAG(VShape) over (partition by MemberID order by TxnID) VShape
from (
    select TxnID, RunningAmount, MemberID,
           case when rn < lagrn and rn < leadrn then 1 else 0 end VShape
    from (
        select *,
               LAG(rn) over (partition by MemberID order by TxnID) lagRn,
               LEAD(rn) over (partition by MemberID order by TxnID) leadRn
        from (
            select TxnID,
                   RunningAmount,
                   MemberID,
                   ROW_NUMBER() over (partition by MemberID order by RunningAmount) rn
            from @tbl
        ) a
    ) a
) a

最后一列VShape指示RunningAmount中的值是否完成了V形(尽管您可以更清楚地了解其含义,而不是每个人都可以弄清楚)。现在,您可以根据RunningAmount过滤值(但值低于或高于100k)。

以下是不具有LAGLEAD函数的SQL Server早期版本的版本:

;with cte as (
    select *,
           ROW_NUMBER() over (partition by MemberID order by RunningAmount) rn 
    from @tbl
), cte2 as (
    select c1.TxnID, c1.RunningAmount, c1.MemberID, c1.rn, c2.rn [lagRn] , c3.rn [leadRn]
    from cte c1 
    left join cte c2 on c1.TxnID = c2.TxnID + 1 and c1.MemberID = c2.MemberID
    left join cte c3 on c1.TxnID = c3.TxnID - 1 and c1.MemberID = c3.MemberID
), cte3 as (
    select TxnID, RunningAmount, MemberID,
           case when rn < lagrn and rn < leadrn then 1 else 0 end VShape
    from cte2
), FinalResult as (
    select c1.TxnID, c1.RunningAmount, c1.MemberID, c2.VShape
    from cte3 c1 
    left join cte3 c2 on c1.TxnID = c2.TxnID + 1 and c1.MemberID = c2.MemberID
)

select fr.*, fr2.RunningAmount RunningAmountLagBy2 from FinalResult fr
left join FinalResult fr2 on fr.TxnID = fr2.TxnID + 2
where fr.RunningAmount > 100000 and fr2.RunningAmount > 100000 and fr.VShape = 1

更新

问题更新后,以下是解决方法:

select TxnID from (
    select *, ROW_NUMBER() over (partition by VShape order by TxnID) CompletesVShape from (
        select TxnID,
               RunningAmount,
               MemberID,
               sum(case when RunningAmount >= 100000 then 1 else 0 end) over (partition by MemberID order by TxnID rows between unbounded preceding and     current row) VShape
        from @tbl
    ) a
) a where VShape > 1 and CompletesVShape = 1

答案 1 :(得分:0)

根据您的问题更新,并假设V形的必要条件是高于和低于运行量> 100000,而中间小于高于和低于运行量,以下是显示如何在2008 sql server中执行此操作的查询。

另请参见 live demo

   ; with firstlargeamount as
(
    select MemberId, minTrxid=min(TxnID)
    from t  
    where RunningAmount>100000
    group by MemberId

)
,tbl as
( 
    select *,
    rn=row_number() over( partition by MemberId order by TxnId)
    from 
    t
)

select t3.*,f.* 
from tbl t1 
join tbl t2
    on 
        t1.memberId=t2.memberid and t1.rn=t2.rn +1
        and t1.RunningAmount<t2.RunningAmount
join tbl t3
    on 
        t1.memberId=t3.memberid and t1.rn=t3.rn -1
        and t1.RunningAmount<t3.RunningAmount
join firstlargeamount f
   on 
       f.Memberid=t2.memberid and f.minTrxid>=t1.TxnID

说明:

第一步是在成员级别生成行号序列,如cte tbl和cte firstlargeamount中的最小限制交易

第二步是双重自连接,以找到满足V形标准的每行上下记录,并与firstlargemount结合以找到满足100000要求的行 请注意,上面和下面的记录只是使用在步骤1中计算的当前记录的行号中的+ 1 / -1来找到的