Sql 看看我在上面链接的其他答案,以获得一个例子或谷歌它 ;with m as (select * from @Table), e as (select * from m where AMT>0), r as (select * from m where AMT<0), ex as ( select *, ROW_NUMBER() over (partition by Client order by [date] ) rn, 1 q from e join FN_NUMBERS(1000) on N<= e.AMT ), rx as ( select *, ROW_NUMBER() over (partition by Client order by [date] ) rn, 1 q from r join FN_NUMBERS(1000) on N<= -r.AMT ), j as ( select isnull(ex.Client, rx.Client) Client, (datediff(DAY, ISNULL(ex.[Date],rx.[Date]), GETDATE()) / 30) dd, (isnull(ex.q,0) - isnull(rx.q,0)) q from ex full join rx on ex.Client = rx.Client and ex.rn = rx.rn where ex.Client is null or rx.Client is null ), mm as ( select j.Client, j.q, isnull(x.n,99) n from j left join (values (0),(1),(2)) x (n) on dd=n ), b as ( select Client, SUM(AMT) balance from m group by Client ), p as ( select b.*, p.[0] as [0-12days], p.[1] as [30-59days], p.[2] as [60-89days], p.[99] as [90days+] from mm pivot (sum(q) for n in ([0],[1],[2],[99])) p left join b on p.Client = b.Client ) select * from p order by 1

Sql 看看我在上面链接的其他答案,以获得一个例子或谷歌它 ;with m as (select * from @Table), e as (select * from m where AMT>0), r as (select * from m where AMT<0), ex as ( select *, ROW_NUMBER() over (partition by Client order by [date] ) rn, 1 q from e join FN_NUMBERS(1000) on N<= e.AMT ), rx as ( select *, ROW_NUMBER() over (partition by Client order by [date] ) rn, 1 q from r join FN_NUMBERS(1000) on N<= -r.AMT ), j as ( select isnull(ex.Client, rx.Client) Client, (datediff(DAY, ISNULL(ex.[Date],rx.[Date]), GETDATE()) / 30) dd, (isnull(ex.q,0) - isnull(rx.q,0)) q from ex full join rx on ex.Client = rx.Client and ex.rn = rx.rn where ex.Client is null or rx.Client is null ), mm as ( select j.Client, j.q, isnull(x.n,99) n from j left join (values (0),(1),(2)) x (n) on dd=n ), b as ( select Client, SUM(AMT) balance from m group by Client ), p as ( select b.*, p.[0] as [0-12days], p.[1] as [30-59days], p.[2] as [60-89days], p.[99] as [90days+] from mm pivot (sum(q) for n in ([0],[1],[2],[99])) p left join b on p.Client = b.Client ) select * from p order by 1,sql,sql-server,pivot,aggregate-functions,Sql,Sql Server,Pivot,Aggregate Functions,再见如果源数据不进行数据透视,这会容易得多。我假设您在某个表中有一个客户、日期和金额,并使用日期将数据透视到日期范围。如果在数据透视之前这样做,会更容易。我怀疑显示的数据是查询的结果。也许你可以提供交易的样本data@xQbert没错。如果数据未透视,您将如何处理它?您可以使用类似于sum(amount)over(partition by client order by date ASC)的窗口函数来生成客户的运行总计,然后仅透视最后一天的最后总计。源表示例(unpivoted)和该格式的一些示

再见

如果源数据不进行数据透视,这会容易得多。我假设您在某个表中有一个客户、日期和金额,并使用日期将数据透视到日期范围。如果在数据透视之前这样做,会更容易。我怀疑显示的数据是查询的结果。也许你可以提供交易的样本data@xQbert没错。如果数据未透视,您将如何处理它?您可以使用类似于
sum(amount)over(partition by client order by date ASC)
的窗口函数来生成客户的运行总计,然后仅透视最后一天的最后总计。源表示例(unpivoted)和该格式的一些示例数据将是一个良好的开端。但即使这样,你也表现出了不错的整数-500-100+600。。。。我怀疑他们是否都表现得那么好,那么你想如何处理部分呢?从未插入的数据开始,您有更好的机会获得所需的结果。模拟一些样本数据和预期结果。@Leettickett根据我对您的解释的理解,对于ABC公司来说,0-29天应该有500个吗?(我指的是你想要的结果)要么我错过了什么,要么你错过了什么。您的查询看起来像我当前用于透视数据的查询。结果就像我的第一个例子。。。但我需要它看起来像我的第二个例子?@Leettickett你能提供你的源数据和第一个枢轴背后的逻辑吗?你的问题缺乏基本信息。每列是什么意思?我上面的代码目前为您提供了每个日期窗口的运行余额以及当前余额。你到底想要什么?目前我的查询只给出了每个老化桶的余额(我相信和你的一样)。但是,如果你看我的例子,你会发现有信用和借记的记录实际上需要进一步的工作;例如,CDE Co在60-89天内有一个贷方余额,在30-59天内有一个借方余额,因此这些余额可以相互应用,在0-29天内只留下余额。我将在原始问题中添加一个源数据示例。@Leettickett然而,说明一个日期窗口应应用于另一个日期窗口的逻辑是什么?当然是在未来?考虑到截至该时间点的所有交易,您是否仅在每个窗口结束时计算当前余额?其想法是先平衡较旧的借方/贷方。例如,如果您有100英镑的贷记(任何年龄),100英镑的贷记60天,另外100英镑的贷记30天,您会将100英镑的贷记应用于100英镑的60天。希望这有意义?太棒了,谢谢你,我需要花一点时间在它上面,但看起来很彻底!
Client Balance 0-29days 30-59days 60-89days 90days+
ABC Co £500    £0       £250      £250      £0
CDE Co £200    £200     £200      £-200     £0
FGH Co £100    £100     £-50      £-500     £600
IJK Co £-100   £100     £0        £0        £-200
Client Balance 0-29days 30-59days 60-89days 90days+
ABC Co £500    £0       £250      £250      £0
CDE Co £200    £200     £0        £0        £0
FGH Co £100    £100     £0        £0        £50
IJK Co £-100   £0       £0        £0        £-100
declare @t table(PaymentDate date
                ,Client nvarchar(50)
                ,Amount decimal(10,2)
                );
insert into @t values
 ('20160920','ABC Co',250),('20161020','ABC Co',250  ),('20161020','CDE Co',200  ),('20161020','CDE Co',200  ),('20160920','CDE Co',-200 ),('20160101','FGH Co',600  ),('20160920','FGH Co',-500 ),('20161020','FGH Co',-100 ),('20161120','FGH Co',100  );

declare @ReportDate date = getdate();

select Client

        -- Data aggregated by each period
        ,sum(Amount) as ClientBalance
        ,sum(case when PaymentDate between dateadd(d,-29,@ReportDate) and @ReportDate then Amount else 0 end) as [0-29 Days]
        ,sum(case when PaymentDate between dateadd(d,-59,@ReportDate) and dateadd(d,-30,@ReportDate) then Amount else 0 end) as [30-59 Days]
        ,sum(case when PaymentDate between dateadd(d,-89,@ReportDate) and dateadd(d,-60,@ReportDate) then Amount else 0 end) as [60-89 Days]
        ,sum(case when PaymentDate <= dateadd(d,-90,@ReportDate) then Amount else 0 end) as [90+ Days]

        ,'' as [ ]

        -- Data aggregated as a rolling periodic balance
        ,sum(Amount) as ClientBalance
        ,sum(case when PaymentDate <= @ReportDate then Amount else 0 end) as [0-29 Days]
        ,sum(case when PaymentDate <= dateadd(d,-30,@ReportDate) then Amount else 0 end) as [30-59 Days]
        ,sum(case when PaymentDate <= dateadd(d,-60,@ReportDate) then Amount else 0 end) as [60-89 Days]
        ,sum(case when PaymentDate <= dateadd(d,-90,@ReportDate) then Amount else 0 end) as [90+ Days]
from @t
group by Client
order by Client;
DECLARE @Table AS TABLE (Client CHAR(6), AMT INT, Date DATE)
INSERT INTO @Table VALUES
('ABC Co',250 ,'2016/09/20')
,('ABC Co',250 ,'2016/10/20')
,('CDE Co',200 ,'2016/11/20')
,('CDE Co',200 ,'2016/10/20')
,('CDE Co',-200,'2016/09/20')
,('FGH Co',600 ,'2016/01/01')
,('FGH Co',-500,'2016/09/20')
,('FGH Co',-50 ,'2016/10/20')
,('FGH Co',100 ,'2016/11/20')
,('IJK Co',-100 ,'2016/01/01')
,('IJK Co',-100 ,'2016/09/20')

;WITH cte AS (
    SELECT
       Client
       ,Date
       ,AMT
       ,CurrentBalance = SUM(AMT) OVER (PARTITION BY Client)
       ,BackwardsRunningTotal = SUM(AMT) OVER (PARTITION BY Client ORDER BY Date DESC)
       ,CurrentBalanceMinusBackwardsRunningTotal = SUM(AMT) OVER (PARTITION BY Client) - SUM(AMT) OVER (PARTITION BY Client ORDER BY Date DESC)
       ,DateGroup = CASE
             WHEN DATEDIFF(day,Date,GETDATE()) BETWEEN 0 AND 29 THEN '0-29days'
             WHEN DATEDIFF(day,Date,GETDATE()) BETWEEN 30 AND 59 THEN '30-59days'
             WHEN DATEDIFF(day,Date,GETDATE()) BETWEEN 60 AND 89 THEN '60-89days'
             WHEN DATEDIFF(day,Date,GETDATE()) >= 90 THEN '90days+'
             ELSE 'Unknown Error'
       END
       ,BalanceAtTime = SUM(AMT) OVER (PARTITION BY Client ORDER BY Date)
    FROM
       @Table
)

, cteWhenCurrentBalanceIsMet AS (
    SELECT
       Client
       ,MaxDate = MAX(DATE)
    FROM
       cte
    WHERE
       CurrentBalanceMinusBackwardsRunningTotal = 0
    GROUP BY
       Client
)

, cteAgedDebtPrepared AS (
    SELECT
       c.Client
       ,Balance = c.CurrentBalance
       ,c.DateGroup
       ,Amt = CASE
          WHEN CurrentBalanceMinusBackwardsRunningTotal = 0
          THEN ISNULL(LAG(CurrentBalanceMinusBackwardsRunningTotal) OVER (PARTITION BY c.Client ORDER BY Date DESC),AMT)
          ELSE AMT
       END
    FROM
       cteWhenCurrentBalanceIsMet m
       INNER JOIN cte c
       ON m.Client = c.Client
       AND m.MaxDate <= c.Date
       AND SIGN(c.AMT) = SIGN(c.CurrentBalance)
)

SELECT *
FROM
    cteAgedDebtPrepared
    PIVOT (
       SUM(Amt)
       FOR DateGroup IN ([0-29days],[30-59days],[60-89days],[90days+])
    ) pvt
ORDER BY
    Client
Client  Balance 0-29days    30-59days   60-89days   90days+
ABC Co  500     NULL        250         250         NULL
CDE Co  200     200         NULL        NULL        NULL
FGH Co  150     100         NULL        NULL        50
IJK Co  -200    NULL        NULL        -100        -100
Create Table Debt (
    Client char(6),
    Amount money,
    [Date] date);

Insert Into Debt 
Values 
('ABC Co', 250,  Convert(date, '20/09/2016', 103)),
('ABC Co', 250,  Convert(date, '20/10/2016', 103)),
('CDE Co', 200,  Convert(date, '20/11/2016', 103)),
('CDE Co', 200,  Convert(date, '20/10/2016', 103)),
('CDE Co', -200, Convert(date, '20/09/2016', 103)),
('FGH Co', 600,  Convert(date, '01/01/2016', 103)),
('FGH Co', -500, Convert(date, '20/09/2016', 103)),
('FGH Co', -50,  Convert(date, '20/10/2016', 103)),
('FGH Co', 100,  Convert(date, '20/11/2016', 103));

With Grouping_cte As (
Select Client, Sum(ABS(Amount)) As Amount, 
    Case When DateDiff(Day, GetDate(), [Date]) > -30 Then '0-29 days'
         When DateDiff(Day, GetDate(), [Date]) > -60 Then '30-59 days'
         When DateDiff(Day, GetDate(), [Date]) > -90 Then '60-89 days'
         Else '90+ days' End As [Date],
    Case When Amount < 0 Then 'In' Else 'Out' End As [Type]
  From Debt
  Group By Client,
    Case When DateDiff(Day, GetDate(), [Date]) > -30 Then '0-29 days'
         When DateDiff(Day, GetDate(), [Date]) > -60 Then '30-59 days'
         When DateDiff(Day, GetDate(), [Date]) > -90 Then '60-89 days'
         Else '90+ days' End,
    Case When Amount < 0 Then 'In' Else 'Out' End),
RunningTotals_cte As (
Select Client, Amount, [Date], [Type],
    Sum(Amount) Over (Partition By Client, [Type] Order By [Date] Desc) - Amount As RunningTotalFrom,
    Sum(Amount) Over (Partition By Client, [Type] Order By [Date] Desc) As RunningTotalTo
  From Grouping_cte),
Allocated_cte As (
Select Outs.Client, Outs.Date, Outs.Amount + IsNull(Sum(x.borrowed_qty),0) As AdjustedAmount
  From (Select * From RunningTotals_cte Where [Type] = 'Out') As Outs
  Left Join (Select * From RunningTotals_cte Where [Type] = 'In') As Ins
    On Ins.RunningTotalFrom < Outs.RunningTotalTo
    And Outs.RunningTotalFrom < Ins.RunningTotalTo
    And Ins.Client = Outs.Client
  Cross Apply (
      Select Case When ins.RunningTotalTo < Outs.RunningTotalTo Then Case When ins.RunningTotalFrom > Outs.RunningTotalFrom  Then -1 * Ins.Amount
                                                                          Else -1 * (Ins.RunningTotalTo - Outs.RunningTotalFrom) End
                  Else Case When Outs.RunningTotalFrom > Ins.RunningTotalFrom Then Outs.Amount
                            Else -1 * (Outs.RunningTotalTo - Ins.RunningTotalFrom) End End) As x (borrowed_qty)
  Group By Outs.Client, Outs.Date, Outs.Amount)
--Select * From Allocated_cte;

Select Client,
    Sum(AdjustedAmount) As Balance,
    Sum(iif([Date] = '0-29 days', AdjustedAmount, Null)) As [0-29 days],
    Sum(iif([Date] = '30-59 days', AdjustedAmount, Null)) As [30-59 days],
    Sum(iif([Date] = '60-89 days', AdjustedAmount, Null)) As [60-89 days],
    Sum(iif([Date] = '90+ days', AdjustedAmount, Null)) As [90+ days]
  From Allocated_cte
  Group By Client;
DECLARE @Table AS TABLE (Client CHAR(6), AMT INT, Date DATE)
INSERT INTO @Table VALUES
('ABC Co',250 ,'2016/09/20')
,('ABC Co',250 ,'2016/10/20')
,('CDE Co',200 ,'2016/11/20')
,('CDE Co',200 ,'2016/10/20')
,('CDE Co',-200,'2016/09/20')
,('FGH Co',600 ,'2016/01/01')
,('FGH Co',-500,'2016/09/20')
,('FGH Co',-50 ,'2016/10/20')
,('FGH Co',100 ,'2016/11/20')
,('IJK Co',-100 ,'2016/01/01')
,('IJK Co',-100 ,'2016/09/20')
,('LMN Co',-200 ,'2016/01/01')
,('LMN Co', 50 ,'2016/06/10')
,('LMN Co',-100 ,'2016/09/20')

;WITH cteRowNumbers AS (
    SELECT *, RowNumber = ROW_NUMBER() OVER (PARTITION BY Client ORDER BY Date DESC)
    FROM
       @Table
)

, cteRecursive AS (
    SELECT
       Client
       ,CurrentBalance = SUM(AMT)
       ,Date = CAST(GETDATE() AS DATE)
       ,Amt = CAST(0 AS INT)
       ,RemainingBalance = SUM(Amt)
       ,AttributedAmt = 0
       ,RowNumber = CAST(0 AS BIGINT)
    FROM
       @Table
    GROUP BY
       Client

    UNION ALL

    SELECT
       r.Client
       ,r.CurrentBalance
       ,c.Date
       ,c.AMT
       ,CASE WHEN SIGN(r.CurrentBalance) = SIGN(c.AMT) THEN r.CurrentBalance - c.AMT ELSE r.RemainingBalance END
       ,CASE
          WHEN SIGN(r.CurrentBalance) <> SIGN(c.AMT) THEN 0
          WHEN ABS(r.RemainingBalance) < ABS(c.AMT) THEN r.RemainingBalance
          ELSE c.AMT END
       ,c.RowNumber
    FROM
       cteRecursive r
       INNER JOIN cteRowNumbers c
       ON r.Client = c.Client
       AND r.RowNumber + 1 = c.RowNumber
    WHERE
       SIGN(r.RemainingBalance) = SIGN(r.CurrentBalance)
)

, ctePrepared AS (
    SELECT
       Client
       ,CurrentBalance
       ,DateGroup = CASE
          WHEN DATEDIFF(day,Date,GETDATE()) BETWEEN 0 AND 29 THEN '0-29days'
          WHEN DATEDIFF(day,Date,GETDATE()) BETWEEN 30 AND 59 THEN '30-59days'
          WHEN DATEDIFF(day,Date,GETDATE()) BETWEEN 60 AND 89 THEN '60-89days'
          WHEN DATEDIFF(day,Date,GETDATE()) >= 90 THEN '90days+'
              ELSE 'Unknown Error'
       END
       ,AttributedAmt
    FROM
       cteRecursive
    WHERE
       RowNumber > 0
       AND AttributedAmt <> 0
)

SELECT *
FROM
    ctePrepared c
    PIVOT (
       SUM(AttributedAmt)
       FOR DateGroup IN ([0-29days],[30-59days],[60-89days],[90days+])
    ) pvt
ORDER BY
    Client
Client  CurrentBalance  0-29days    30-59days   60-89days   90days+
ABC Co  500            NULL         250         250         NULL
CDE Co  200            200          NULL        NULL         NULL
FGH Co  150            100          NULL        NULL         50
IJK Co  -200             NULL        NULL   -100         -100
LMN Co  -250             NULL        NULL   -100         -150
DECLARE @Table AS TABLE (Client CHAR(6), AMT INT, Date DATE)
INSERT INTO @Table VALUES
('ABC Co',250 ,'2016/09/20')
,('ABC Co',250 ,'2016/10/20')
,('CDE Co',200 ,'2016/11/20')
,('CDE Co',200 ,'2016/10/20')
,('CDE Co',-200,'2016/09/20')
,('FGH Co',600 ,'2016/01/01')
,('FGH Co',-500,'2016/09/20')
,('FGH Co',-50 ,'2016/10/20')
,('FGH Co',100 ,'2016/11/20')
,('IJK Co',-200 ,'2016/01/01')
,('IJK Co',100 ,'2016/09/20')
;with
m as (select * from @Table),
e as (select * from m where AMT>0),
r as (select * from m where AMT<0),
ex as (
    select *, ROW_NUMBER() over (partition by Client order by [date] ) rn, 1 q
    from e
    join FN_NUMBERS(1000) on N<= e.AMT
),
rx as (
    select *, ROW_NUMBER() over (partition by Client order by [date] ) rn, 1 q
    from r
    join FN_NUMBERS(1000) on N<= -r.AMT
),
j as (
select 
    isnull(ex.Client, rx.Client) Client, 
    (datediff(DAY, ISNULL(ex.[Date],rx.[Date]), GETDATE()) / 30) dd,
    (isnull(ex.q,0) - isnull(rx.q,0)) q
from ex
full join rx on ex.Client = rx.Client and ex.rn = rx.rn 
where ex.Client is null or  rx.Client is null
),
mm as (
    select j.Client, j.q, isnull(x.n,99) n
    from j
    left join (values (0),(1),(2)) x (n) on dd=n
),
b as (
    select Client, SUM(AMT) balance
    from m
    group by Client
),
p as (
    select b.*, p.[0] as [0-12days], p.[1] as [30-59days], p.[2] as [60-89days], p.[99] as [90days+]
    from mm
    pivot (sum(q) for n in ([0],[1],[2],[99])) p
    left join b on p.Client = b.Client
)
select *
from p
order by 1
Client  balance 0-12days    30-59days   60-89days   90days+
ABC Co  500     NULL        250         250         NULL
CDE Co  200     200         NULL        NULL        NULL
FGH Co  150     100         NULL        NULL        50
IJK Co  -100    NULL        NULL        NULL        -100