在多行中拆分行

Split Rows in multiple rows

我需要把一行分成几行

例如,我有这个结果,它表示用户应该分几期付款的总金额,每期付款都有某个日期,基于分期付款间隔,所以每个 TotalSum 除以 InstallsmentNoTotal,即每个 Installment金额,对于第一期的 InstallmentDate 是 FirstInstallmentDate,但对于每一期,我们应该添加 InstallsmentInterval 天数。

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

我尝试使用 Cursors、Cross Apply,但我无法管理工作。

提前感谢您的帮助

您可以使用递归查询:

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, ...)

这是符合要求的基于“计数”table 的方法。这种方法是一种简单有效的基于数字或计数 table 计算前向的方法。在这种情况下,我将其设置为 6 个值,但它可以增加到任何需要的值(以满足最大 InstallsmentNoTotal)。基于 Imo 计数的方法更简单、更易读,并且(在极限内)更快。

数据

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

你可以通过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          |
+---------+---------------+------------------+---------------------+