T-SQL更有效地聚合连续日期

时间:2017-04-28 21:33:44

标签: sql sql-server tsql cursor

我需要在连续日期汇总一笔金额。我已经看到类似问题的解决方案将返回开始和结束日期,但不需要在这些范围之间聚合数据。由于所涉及的数据非常庞大,使得简单的自连接花费了不切实际的时间(特别是因为开始和结束日期字段未编入索引),这进一步复杂化了

我有一个涉及游标的解决方案,但我一般都认为游标总是可以更有效地替换为执行速度更快的联接,但到目前为止我尝试过的任何解决方案都接近于给出了一个查询我需要的数据至少需要一个小时,我的光标解决方案大约需要10秒钟。所以我在问是否有更有效的答案。

并且数据包括买入和卖出交易,并且返回的每行累计连续日期还需要列出在第一次购买连续买入交易之前发生的最后卖出的交易ID。

数据的一个例子:

            bot bot = new bot();
            bot.clan = JsonConvert.DeserializeObject<clan>(json.ToString());
            bot.player = new List<player>();

            //assign aliases
             foreach (Memberlist member in bot.clan.memberList) {
               player a = new player();
               a.tag = member.tag;
               bot.player.Add(a);
            }

应该有以下结果:

+------------------+------------+------------+------------------+--------------------+
| TRANSACTION_TYPE | TRANS_ID   | StartDate  | EndDate          | Amount             |
+------------------+------------+------------+------------------+--------------------+
| sell             | 100        | 2/16/16    | 2/18/18          | $100.00            |
| sell             | 101        | 3/1/16     | 6/6/16           | $121.00            |
| buy              | 102        | 6/10/16    | 6/12/16          | $22.00             |
| buy              | 103        | 6/12/16    | 6/14/16          | $0.35              |
| buy              | 104        | 6/29/16    | 7/2/16           | $5.00              |
| sell             | 105        | 7/3/16     | 7/6/16           | $115.00            |
| buy              | 106        | 7/8/16     | 7/9/16           | $200.00            |
| sell             | 107        | 7/10/16    | 7/13/16          | $4.35              |
| sell             | 108        | 7/17/16    | 7/20/16          | $0.50              |
| buy              | 109        | 7/25/16    | 7/29/16          | $33.00             |
| buy              | 110        | 7/29/16    | 8/1/16           | $75.00             |
| buy              | 111        | 8/1/16     | 8/3/16           | $0.33              |
| sell             | 112        | 9/1/16     | 9/2/16           | $99.00             |
+------------------+------------+------------+------------------+--------------------+

现在我使用查询将数据拆分为买入和卖出,只需浏览买入数据,按照我的方式进行汇总,每次在日期中找到休息时插入到返回表中,然后我逐步完成出售表,直到我在购买开始日期之前到达最后一次卖出。

通过游标线性行走给我一个n的计算时间。即使游标的效率低几个数量级,它仍然在n中计算,而我怀疑我需要做的连接会给我至少n log n。由于我正在处理大量数据,如果超出线性时间,游标的低效率就会被淹没。

1 个答案:

答案 0 :(得分:0)

如果我假设交易ID随日期增加,那么您可以使用累计最大值获得上次销售日期。然后,可以通过使用类似的逻辑找到邻接,但首先是滞后:

with cte as (
      select t.*,
             sum(case when transaction_type = 'sell' then trans_id end) over
                 (order by trans_id) as last_sell,
             lag(enddate) over (partition by transaction_type order by trans_id) as prev_enddate
      from t
     )
select last_sell, min(startdate) as startdate, max(enddate) as enddate,
       sum(amount) as amount
from (select cte.*,
             sum(case when startdate = dateadd(day, 1, prev_enddate) then 0 else 1 end) over (partition by last_sell order by trans_id) as grp
      from cte 
      where transaction_type = 'buy'
     ) x
group by last_sell, grp;