TSQL运行总计包含开始日期和结束日期

时间:2015-03-04 12:29:13

标签: sql-server tsql running-total

我有两张桌子,

表-A

+---------+----+------------+------------+-----------+
| SurrKey | ID | StartDate  |  EndDate   | Allotment |
+---------+----+------------+------------+-----------+
|       1 |  1 | 2015-01-01 | 2015-01-31 |      1000 |
|       2 |  1 | 2015-01-15 | 2015-02-15 |      1500 |
|       3 |  2 | 2015-01-01 | 2015-01-31 |      1200 |
|       4 |  2 | 2015-02-10 | 2015-03-10 |      1000 |
|       5 |  3 | 2015-01-01 | 2015-01-31 |      1000 |
|       6 |  3 | 2015-01-15 | 2015-02-14 |      1500 |
+---------+----+------------+------------+-----------+

表-B

+----+------------+------+
| ID |    Date    | Used |
+----+------------+------+
|  1 | 2015-01-01 |  800 |
|  1 | 2015-01-14 |  300 |
|  1 | 2015-01-15 |  100 |
|  1 | 2015-01-18 |  200 |
|  2 | 2015-01-01 |  700 |
|  2 | 2015-01-14 |  300 |
|  2 | 2015-01-15 |  150 |
|  2 | 2015-02-05 |   90 |
|  2 | 2015-02-11 |  100 |
|  3 | 2015-01-01 |  900 |
|  3 | 2015-01-15 |  150 |
+----+------------+------+

生成SQL查询以生成以下输出。

+------------+----+------------+------+---------------+--------------------+
| Row_number | ID | Date       | Used | Running Total | RemainingAllotment |
+------------+----+------------+------+---------------+--------------------+
| 1          | 1  | 2015-01-01 | 800  | 800           | 200                |
| 2          | 1  | 2015-01-14 | 300  | 1100          | -100               |
| 3          | 1  | 2015-01-15 | 100  | 100           | 1400               |
| 4          | 1  | 2015-01-18 | 200  | 300           | 1200               |
| 5          | 2  | 2015-01-01 | 700  | 700           | 500                |
| 6          | 2  | 2015-01-14 | 300  | 1000          | 200                |
| 7          | 2  | 2015-01-15 | 150  | 1150          | 50                 |
| 8          | 2  | 2015-02-05 | 90   | 90            | -90                |
| 9          | 2  | 2015-02-11 | 100  | 100           | 900                |
| 10         | 3  | 2015-01-01 | 900  | 900           | 100                |
| 11         | 3  | 2015-01-15 | 100  | 1000          | 0                  |
| 12         | 3  | 2015-01-15 | 50   | 50            | 1450               |
+------------+----+------------+------+---------------+--------------------+

所需输出的一些细节:

  • 在Row_number 2上,它是负100,因为他用完了所有的hist 分配
  • 在Row_number 3上,他从这一天开始就有了新的分配, 应该在此ID上重置运行总计
  • 在Row_number 8上,其负90,重置此ID的运行总计, 因为Surrkey 3已经过期,而startdate将只在2015-02-10
  • 在Row_number 9上,表A上的Surrkey 4的新用法

附加要求。我为此编辑了样本表

  • 在Row_Number 11和12上,有相同的日期和相同的ID,因为在使用下一个之前必须使用所有剩余的分配,在这种情况下,Surrkey 6。

1 个答案:

答案 0 :(得分:1)

如果您可以使用窗口函数,那么您可以这样做:

DECLARE @A TABLE
    (
      SurrKey INT ,
      ID INT ,
      StartDate DATE ,
      EndDate DATE ,
      Allotment MONEY
    )
DECLARE @B TABLE
    (
      ID INT ,
      Date DATE ,
      Used MONEY
    )


INSERT  INTO @A
VALUES  ( 1, 1, '20150101', '20150131', 1000 ),
        ( 2, 1, '20150115', '20150215', 1500 ),
        ( 3, 2, '20150101', '20150131', 1200 ),
        ( 4, 2, '20150210', '20150310', 1000 )


INSERT  INTO @B
VALUES  ( 1, '20150101', 800 ),
        ( 1, '20150114', 300 ),
        ( 1, '20150115', 100 ),
        ( 1, '20150118', 200 ),
        ( 2, '20150101', 700 ),
        ( 2, '20150114', 300 ),
        ( 2, '20150115', 150 ),
        ( 2, '20150205', 90 ),
        ( 2, '20150211', 100 );
WITH    cte
          AS ( SELECT   ROW_NUMBER() OVER ( ORDER BY ( SELECT 1 ) ) AS RN ,
                        b.ID ,
                        b.Date ,
                        b.Used ,
                        SUM(b.Used) OVER ( PARTITION BY b.ID, o.SurrKey ORDER BY b.Date ) AS RTotal ,
                        -SUM(b.Used) OVER ( PARTITION BY b.ID, o.SurrKey ORDER BY b.Date ) + o.Allotment AS Remaining
               FROM     @B b
                        OUTER APPLY ( SELECT TOP 1 *
                                      FROM      @A a
                                      WHERE     a.ID = b.ID
                                                AND b.Date >= a.StartDate
                                      ORDER BY  a.StartDate DESC
                                    ) o
             )
    SELECT  * FROM    cte

输出:

RN  ID  Date        Used    RTotal   Remaining
1   1   2015-01-01  800.00  800.00   200.00
2   1   2015-01-14  300.00  1100.00  -100.00
3   1   2015-01-15  100.00  100.00   1400.00
4   1   2015-01-18  200.00  300.00   1200.00
5   2   2015-01-01  700.00  700.00   500.00
6   2   2015-01-14  300.00  1000.00  200.00
7   2   2015-01-15  150.00  1150.00  50.00
8   2   2015-02-05  90.00   1240.00  -40.00
9   2   2015-02-11  100.00  100.00   900.00

修改

对于SQL 2008,您可以使用:

WITH    cte
          AS ( SELECT   ROW_NUMBER() OVER ( ORDER BY ( SELECT 1 ) ) AS RN ,
                        b.ID ,
                        b.Date ,
                        b.Used ,
                        o.SurrKey ,
                        o.Allotment
               FROM     @B b
                        OUTER APPLY ( SELECT TOP 1 *
                                      FROM      @A a
                                      WHERE     a.ID = b.ID
                                                AND b.Date >= a.StartDate
                                      ORDER BY  a.StartDate DESC
                                    ) o
             ),
        cte1
          AS ( SELECT   cte.RN ,
                        cte.ID ,
                        cte.Date ,
                        cte.Used ,
                        ( SELECT    SUM(Used)
                          FROM      cte i
                          WHERE     i.ID = cte.ID
                                    AND i.SurrKey = cte.SurrKey
                                    AND i.Date <= cte.Date
                        ) AS RToTal ,
                        cte.Allotment
                        - ( SELECT  SUM(Used)
                            FROM    cte i
                            WHERE   i.ID = cte.ID
                                    AND i.SurrKey = cte.SurrKey
                                    AND i.Date <= cte.Date
                          ) AS Remaining
               FROM     cte
             )
    SELECT  * FROM    cte1