将行拆分为多行

时间:2020-09-07 22:22:50

标签: sql sql-server datetime recursive-query

我需要将一行分成几行

例如,我有一个结果,该结果表示用户应分几期支付的总金额,并且每期是基于分期间隔的到期日期,因此每个TotalSum除以InstallsmentNoTotal,即每个分期付款金额,对于首期付款的InstallmentDate,则为FirstInstallmentDate,但对于其他每期付款,我们都应添加InstallsmentInterval Days。

DECLARE @temTable TABLE
(
    Id INT,
    TotalSum DECIMAL(18, 0),
    InstallsmentNoTotal INT,
    InstallsmentInterval INT,
    FirstInstallmentDate DATE
);

INSERT INTO @temTable
(
    Id,
    TotalSum,
    InstallsmentNoTotal,
    InstallsmentInterval,
    FirstInstallmentDate
)
VALUES 
(1, 6000, 3, 30, '2020-08-01'),
(2, 8000, 2, 60, '2020-10-01'),
(3, 5000, 1,  0, '2020-08-01')

SELECT * FROM @temTable

Id  TotalSum    InstallsmentNoTotal   InstallsmentInterval  FirstInstallmentDate
1    6000                3                     30                2020-08-01 
2    8000                2                     60                2020-10-01
3    5000                1                      0                2020-08-01

我需要像这样显示每一行的数据:

SaleId     InstallmentNo   InstallmensAmount   NextInstallmentDate
   1              1             2000              2020-08-01
   1              2             2000              2020-09-01
   1              3             2000              2020-10-01
   2              1             4000              2020-10-01
   2              2             4000              2020-12-01
   3              1             5000              2020-08-01

我尝试使用“光标”,“交叉应用”,但无法管理工作。

预先感谢您的帮助

3 个答案:

答案 0 :(得分:3)

您可以使用递归查询:

with cte as (
    select 
        id saleId, 
        1 InstallmentNo,
        TotalSum / InstallsmentNoTotal InstallmentAmount,
        FirstInstallmentDate NextInstallmentDate,
        InstallsmentInterval,
        InstallsmentNoTotal
    from @temTable
    union all
    select 
        saleId,
        InstallmentNo + 1,
        InstallmentAmount,
        cast(dateadd(day, InstallsmentInterval, NextInstallmentDate) as date),
        InstallsmentInterval,
        InstallsmentNoTotal
    from cte
    where InstallmentNo < InstallsmentNoTotal
)
select saleId, InstallmentAmount, InstallmentAmount, NextInstallmentDate
from cte
order by saleId, InstallmentNo

有关示例数据,this returns

saleId | InstallmentAmount | InstallmentAmount | NextInstallmentDate
-----: | ----------------: | ----------------: | :------------------
     1 |  2000.00000000000 |  2000.00000000000 | 2020-08-01         
     1 |  2000.00000000000 |  2000.00000000000 | 2020-08-31         
     1 |  2000.00000000000 |  2000.00000000000 | 2020-09-30         
     2 |  4000.00000000000 |  4000.00000000000 | 2020-10-01         
     2 |  4000.00000000000 |  4000.00000000000 | 2020-11-30         
     3 |  5000.00000000000 |  5000.00000000000 | 2020-08-01         

您可以看到日期运算不是您想要的。如果要按月增加日期,则应存储数月而不是数天(并在CTE的递归成员中用dateadd(day, ...)修改dateadd(month, ...)

答案 1 :(得分:2)

这是一种满足要求的基于“ tally”表的方法。这种方法是一种简单有效的方法,可基于数字或理货表格进行向前计算。在这种情况下,我将其设置为6个值,但可以将其增加到所需的任何值(以满足最大的InstallsmentNoTotal)。基于Imo tally的方法更简单,更具可读性,并且(在极限情况下)更快。

数据

create table #temTable
(
    Id INT,
    TotalSum DECIMAL(18, 0),
    InstallsmentNoTotal INT,
    InstallsmentInterval INT,
    FirstInstallmentDate DATE
);

INSERT INTO #temTable
(
    Id,
    TotalSum,
    InstallsmentNoTotal,
    InstallsmentInterval,
    FirstInstallmentDate
)
VALUES 
(1, 6000, 3, 30, '2020-08-01'),
(2, 8000, 2, 60, '2020-10-01'),
(3, 5000, 1,  0, '2020-08-01');

查询

select id SaleId, t.TotalSum/t.InstallsmentNoTotal InstallmentAmount,
       dateadd(month, (InstallsmentInterval/30)*(tally.n-1), FirstInstallmentDate) NextInstallmentDate
from #temTable t
     cross apply
     (select n from (values (1),(2),(3),(4),(5),(6)) v(n)
      where n<=t.InstallsmentNoTotal) tally;

输出

SaleId  InstallmentAmount   NextInstallmentDate
1       2000.00000000000    2020-08-01
1       2000.00000000000    2020-09-01
1       2000.00000000000    2020-10-01
2       4000.00000000000    2020-10-01
2       4000.00000000000    2020-12-01
3       5000.00000000000    2020-08-01

答案 2 :(得分:1)

您可以要求CTE获得结果集。

;WITH CTE_Installments as
(
SELECT Id,TotalSum/InstallsmentNoTotal AS InstallmentSum
,1 as CurrentinstallmentNo, InstallsmentNoTotal, 
dateadd(dd,InstallsmentInterval,FirstInstallmentDate) as nextInstallmentDate, InstallsmentInterval  FROM @temTable
union all
SELECT Id, InstallmentSum, CurrentInstallmentNo+1 as currentinstallmentNo, InstallsmentNoTotal,
dateadd(dd,InstallsmentInterval,nextInstallmentDate) as nextInstallmentDate, InstallsmentInterval
from CTE_Installments
where CurrentinstallmentNo < InstallsmentNoTotal
)
SELECT Id as salesId, CurrentinstallmentNo as InstallmentNo, InstallmentSum,nextInstallmentDate
FROM CTE_Installments
order by Id

+---------+---------------+------------------+---------------------+
| salesId | InstallmentNo |  InstallmentSum  | nextInstallmentDate |
+---------+---------------+------------------+---------------------+
|       1 |             1 | 2000.00000000000 | 2020-08-31          |
|       1 |             2 | 2000.00000000000 | 2020-09-30          |
|       1 |             3 | 2000.00000000000 | 2020-10-30          |
|       2 |             1 | 4000.00000000000 | 2020-11-30          |
|       2 |             2 | 4000.00000000000 | 2021-01-29          |
|       3 |             1 | 5000.00000000000 | 2020-08-01          |
+---------+---------------+------------------+---------------------+