【问题标题】:SQL Server - split record over multiple months into records by one monthSQL Server - 将多个月的记录拆分为一个月的记录
【发布时间】:2017-02-27 22:58:05
【问题描述】:

假设我有下表:

ID | user | from       | to         | loan
1  | BB   | 01/01/2016 | 01/05/2016 | 50
2  | AD   | 01/01/2016 | 01/03/2016 | 25
3  | AD   | 01/03/2016 | 17/05/2016 | 30

此表中的loan 是每月一次。所以用户 BB 从 01/01/2016 到 01/05/2016 每月赚取 50 个硬币。我想把它分成以下记录:

 ID | user | from       | to         | loan
 1  | BB   | 01/01/2016 | 01/02/2016 | 50
 1  | BB   | 01/02/2016 | 01/03/2016 | 50
 1  | BB   | 01/03/2016 | 01/04/2016 | 50
 1  | BB   | 01/04/2016 | 01/05/2016 | 50
 2  | AD   | 01/01/2016 | 01/02/2016 | 25
 2  | AD   | 01/02/2016 | 01/03/2016 | 25
 3  | AD   | 01/03/2016 | 01/04/2016 | 30
 3  | AD   | 01/04/2016 | 01/05/2016 | 30
 3  | AD   | 01/05/2016 | 17/05/2016 | 30

关于如何做到这一点的任何想法/建议?

【问题讨论】:

  • 递归 CTE 或您加入数据的日历表
  • 为什么ID为3的记录不分成3条记录(01/03/2016 - 01/04/201601/04/2016 - 01/05/201601/05/2016 - 17/05/2016)?
  • @GarethD 糟糕,我错过了那里的记录。已编辑。

标签: sql-server tsql


【解决方案1】:

你可以试试这个:

SET DATEFORMAT dmy;
DECLARE @Dummy TABLE(ID INT,[user] VARCHAR(100),[from] DATE,[to] DATE,loan INT);
INSERT INTO @Dummy VALUES
 (1,'BB','01/01/2016','01/05/2016',50)
,(2,'AD','01/01/2016','01/03/2016',25)
,(3,'AD','01/03/2016','17/05/2016',30);

DECLARE @FirstDay DATE='01/01/2016';

WITH SomeNumbers AS --replace this with a values/tally/numbers/date table
(
    SELECT * FROM(VALUES(0),(1),(2),(3)) AS t(Nr)
)


SELECT DISTINCT
       x.FirstOfMonth
      ,FittingData.*
FROM SomeNumbers
CROSS APPLY(SELECT DATEADD(MONTH,SomeNumbers.Nr,@FirstDay) AS FirstOfMonth) AS x
CROSS APPLY(SELECT * FROM @Dummy AS d WHERE x.FirstOfMonth>=d.[from] AND x.FirstOfMonth<d.[to]) AS FittingData
WHERE ID IS NOT NULL
ORDER BY ID,[from]

结果

+--------------+----+------+------------+------------+------+
| FirstOfMonth | ID | user | from       | to         | loan |
+--------------+----+------+------------+------------+------+
| 2016-01-01   | 1  | BB   | 2016-01-01 | 2016-05-01 | 50   |
+--------------+----+------+------------+------------+------+
| 2016-02-01   | 1  | BB   | 2016-01-01 | 2016-05-01 | 50   |
+--------------+----+------+------------+------------+------+
| 2016-03-01   | 1  | BB   | 2016-01-01 | 2016-05-01 | 50   |
+--------------+----+------+------------+------------+------+
| 2016-04-01   | 1  | BB   | 2016-01-01 | 2016-05-01 | 50   |
+--------------+----+------+------------+------------+------+
| 2016-01-01   | 2  | AD   | 2016-01-01 | 2016-03-01 | 25   |
+--------------+----+------+------------+------------+------+
| 2016-02-01   | 2  | AD   | 2016-01-01 | 2016-03-01 | 25   |
+--------------+----+------+------------+------------+------+
| 2016-03-01   | 3  | AD   | 2016-03-01 | 2016-05-17 | 30   |
+--------------+----+------+------------+------------+------+
| 2016-04-01   | 3  | AD   | 2016-03-01 | 2016-05-17 | 30   |
+--------------+----+------+------------+------------+------+

【讨论】:

    【解决方案2】:
        ;WITH testtable(ID,[USER],[from],[to],loan)AS(
        SELECT 1,'BB',CONVERT(DATE,'01/01/2016'),CONVERT(DATE,'01/05/2016'),50 UNION all
        SELECT 2,'AD','01/01/2016','01/03/2016',25 UNION all
        SELECT 3 ,'AD','01/03/2016','01/05/2016',30
     )
     SELECT t.ID,t.[USER],DATEADD(d,sv.number,t.[FROM]) AS [From],dateadd(d,sv.number+1,t.[FROM]) AS [To],t.loan FROM testtable AS t
     INNER JOIN master.dbo.spt_values AS sv ON sv.type='P' AND sv.number BETWEEN 0 AND DATEDIFF(d,t.[FROM],t.[TO])-1
    
    ID USER 从 到 贷款 ----------- ---- ---------- ---------- ------------ 1 BB 2016-01-01 2016-01-02 50 1 BB 2016-01-02 2016-01-03 50 1 BB 2016-01-03 2016-01-04 50 1 BB 2016-01-04 2016-01-05 50 2 公元 2016-01-01 2016-01-02 25 2 公元 2016-01-02 2016-01-03 25 3 AD 2016-01-03 2016-01-04 30 3 AD 2016-01-04 2016-01-05 30

    【讨论】:

      猜你喜欢
      • 2020-10-19
      • 1970-01-01
      • 2012-07-16
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2012-06-10
      • 1970-01-01
      • 2012-12-20
      相关资源
      最近更新 更多