使用 EOMONTH 系列将开始日期扩展到结束日期
Expand Start Date to End Date with Series of EOMONTHs
我有一个数据 table 包含 id,开始日期和结束日期都与之关联。
RowNo AcNo StartDate EndDate
1 R125 01/10/2017 30/09/2020
2 R126 01/10/2017 30/09/2018
3 R127 01/10/2017 30/09/2019
4 R128 01/10/2017 30/09/2020
我需要扩展(即逆轴)这个 table 以允许每个 AcNo 的开始日期和结束日期(含)之间的每个 eomonth 一行。行号不重要。
AcNo EOMONTHs
R125 Oct 17
R125 Nov 17
R125 Dec 17
R125 Jan 18
R125 Feb 18
R125 Mar 18
...
R128 Apr 20
R128 May 20
R128 Jun 20
R128 Jul 20
R128 Aug 20
R128 Sep 20
我可以用这样的一对公式来计算每一行,
'in F2
=IF(ROW(1:1)-1<DATEDIF(C, D, "m"), B, TEXT(,))
'in G2
=IF(ROW(1:1)-1<DATEDIF(C, D, "m"), EOMONTH(C, ROW(1:1)-1), TEXT(,))
'F2:G2 filled down
但是我有数千行 AcNos,这对单独的行执行起来很笨重。
我还使用 VBA 的 DateDiff 为各个行形成循环。
Dim m As Long, ms As Long
With Worksheets("Sheet2")
.Range("F1:G1") = Array("AcNo", "EOMONTHs")
ms = DateDiff("m", .Cells(2, "C").Value2, .Cells(2, "D").Value2)
For m = 1 To ms + 1
.Cells(m, "M") = .Cells(2, "B").Value2
.Cells(m, "N").Formula = "=EOMONTH(C, " & m - 1 & ")"
Next m
End With
同样,这一次只会扩展一行。
我如何遍历将每个系列堆叠成一列的行?欢迎对我的公式或代码提出任何调整建议。
尝试将其作为嵌套的 For ... Next 循环使用 DateDiff 来确定月数。在数组中收集渐进值将在将它们转储回工作表之前加快执行速度。
Option Explicit
Sub eoms()
Dim a As Long, m As Long, ms As Long, vals As Variant
With Worksheets("Sheet2")
.Range("F1:G1") = Array("AcNo", "EOMONTHs")
For a = 2 To .Cells(.Rows.Count, "B").End(xlUp).Row
ms = DateDiff("m", .Cells(a, "C").Value2, .Cells(a, "D").Value2)
ReDim vals(1 To ms + 1, 1 To 2)
For m = 1 To ms + 1
vals(m, 1) = .Cells(a, "B").Value2
vals(m, 2) = DateSerial(Year(.Cells(a, "C").Value2), _
Month(.Cells(a, "C").Value2) + m, _
0)
Next m
.Cells(.Rows.Count, "F").End(xlUp).Offset(1, 0).Resize(UBound(vals, 1), UBound(vals, 2)) = vals
Next a
.Range(.Cells(2, "G"), .Cells(.Rows.Count, "G").End(xlUp)).NumberFormat = "mmm yy"
End With
End Sub
VBA 的 DateSerial 可以通过将日期设置为下个月的零来用作 EOMONTH 生成器。
请注意下图中生成的月份是系列中每个月的 EOMONTH,格式为 mmm yy 单元格编号。
只是因为你似乎在征求多种选择,这里有一个没有 VBA:
- 用公式向右展开 table(此处使用结构化引用):
=IF(EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A))<Table1[@[EndDate]:[EndDate]],EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A)),"")
- 使用
Power Query
或 Data Get & Transform
取消透视除了前两列之外的所有内容:(在 GUI 中很容易完成,但我出于兴趣粘贴了下面的代码)
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"RowNo", Int64.Type}, {"AcNo", type text}, {"StartDate", type datetime}, {"EndDate", type datetime}, {"Column1", type datetime}, {"Column2", type datetime}, {"Column3", type datetime}, {"Column4", type datetime}, {"Column5", type datetime}, {"Column6", type datetime}, {"Column7", type datetime}, {"Column8", type datetime}, {"Column9", type datetime}, {"Column10", type datetime}, {"Column11", type datetime}, {"Column12", type datetime}, {"Column13", type datetime}, {"Column14", type datetime}, {"Column15", type datetime}, {"Column16", type datetime}, {"Column17", type datetime}, {"Column18", type datetime}, {"Column19", type datetime}, {"Column20", type datetime}, {"Column21", type datetime}, {"Column22", type datetime}, {"Column23", type datetime}, {"Column24", type datetime}, {"Column25", type datetime}, {"Column26", type datetime}, {"Column27", type datetime}, {"Column28", type datetime}, {"Column29", type datetime}, {"Column30", type datetime}, {"Column31", type datetime}, {"Column32", type datetime}, {"Column33", type datetime}, {"Column34", type datetime}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"RowNo", "AcNo"}, "Attribute", "Value"),
#"Removed Columns" = Table.RemoveColumns(#"Unpivoted Other Columns",{"Attribute"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Value", "EOM Date"}}),
#"Changed Type1" = Table.TransformColumnTypes(#"Renamed Columns",{{"EOM Date", type date}})
in
#"Changed Type1"
- 按 AcNo 然后按日期对结果进行排序:
请注意,以这种方式完成后,第一个日期实际上是 BOM 日期,但如果您将它们格式化为结果中的格式,嗯嗯,它看起来是一样的。如果这是一个问题,事情很容易改变。
如果不希望将第一个月作为 BOM 日期:
- 将公式更改为:
=IF(EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A)-1)<=Table1[@[EndDate]:[EndDate]],EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A)-1),"")
- 执行
Data Get & Transform
时,删除Query GUI编辑器中的StartDate
列,因为这不会影响当时的其他列。
我有一个数据 table 包含 id,开始日期和结束日期都与之关联。
RowNo AcNo StartDate EndDate
1 R125 01/10/2017 30/09/2020
2 R126 01/10/2017 30/09/2018
3 R127 01/10/2017 30/09/2019
4 R128 01/10/2017 30/09/2020
我需要扩展(即逆轴)这个 table 以允许每个 AcNo 的开始日期和结束日期(含)之间的每个 eomonth 一行。行号不重要。
AcNo EOMONTHs
R125 Oct 17
R125 Nov 17
R125 Dec 17
R125 Jan 18
R125 Feb 18
R125 Mar 18
...
R128 Apr 20
R128 May 20
R128 Jun 20
R128 Jul 20
R128 Aug 20
R128 Sep 20
我可以用这样的一对公式来计算每一行,
'in F2
=IF(ROW(1:1)-1<DATEDIF(C, D, "m"), B, TEXT(,))
'in G2
=IF(ROW(1:1)-1<DATEDIF(C, D, "m"), EOMONTH(C, ROW(1:1)-1), TEXT(,))
'F2:G2 filled down
但是我有数千行 AcNos,这对单独的行执行起来很笨重。
我还使用 VBA 的 DateDiff 为各个行形成循环。
Dim m As Long, ms As Long
With Worksheets("Sheet2")
.Range("F1:G1") = Array("AcNo", "EOMONTHs")
ms = DateDiff("m", .Cells(2, "C").Value2, .Cells(2, "D").Value2)
For m = 1 To ms + 1
.Cells(m, "M") = .Cells(2, "B").Value2
.Cells(m, "N").Formula = "=EOMONTH(C, " & m - 1 & ")"
Next m
End With
同样,这一次只会扩展一行。
我如何遍历将每个系列堆叠成一列的行?欢迎对我的公式或代码提出任何调整建议。
尝试将其作为嵌套的 For ... Next 循环使用 DateDiff 来确定月数。在数组中收集渐进值将在将它们转储回工作表之前加快执行速度。
Option Explicit
Sub eoms()
Dim a As Long, m As Long, ms As Long, vals As Variant
With Worksheets("Sheet2")
.Range("F1:G1") = Array("AcNo", "EOMONTHs")
For a = 2 To .Cells(.Rows.Count, "B").End(xlUp).Row
ms = DateDiff("m", .Cells(a, "C").Value2, .Cells(a, "D").Value2)
ReDim vals(1 To ms + 1, 1 To 2)
For m = 1 To ms + 1
vals(m, 1) = .Cells(a, "B").Value2
vals(m, 2) = DateSerial(Year(.Cells(a, "C").Value2), _
Month(.Cells(a, "C").Value2) + m, _
0)
Next m
.Cells(.Rows.Count, "F").End(xlUp).Offset(1, 0).Resize(UBound(vals, 1), UBound(vals, 2)) = vals
Next a
.Range(.Cells(2, "G"), .Cells(.Rows.Count, "G").End(xlUp)).NumberFormat = "mmm yy"
End With
End Sub
VBA 的 DateSerial 可以通过将日期设置为下个月的零来用作 EOMONTH 生成器。
请注意下图中生成的月份是系列中每个月的 EOMONTH,格式为 mmm yy 单元格编号。
只是因为你似乎在征求多种选择,这里有一个没有 VBA:
- 用公式向右展开 table(此处使用结构化引用):
=IF(EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A))<Table1[@[EndDate]:[EndDate]],EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A)),"")
- 使用
Power Query
或Data Get & Transform
取消透视除了前两列之外的所有内容:(在 GUI 中很容易完成,但我出于兴趣粘贴了下面的代码)
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"RowNo", Int64.Type}, {"AcNo", type text}, {"StartDate", type datetime}, {"EndDate", type datetime}, {"Column1", type datetime}, {"Column2", type datetime}, {"Column3", type datetime}, {"Column4", type datetime}, {"Column5", type datetime}, {"Column6", type datetime}, {"Column7", type datetime}, {"Column8", type datetime}, {"Column9", type datetime}, {"Column10", type datetime}, {"Column11", type datetime}, {"Column12", type datetime}, {"Column13", type datetime}, {"Column14", type datetime}, {"Column15", type datetime}, {"Column16", type datetime}, {"Column17", type datetime}, {"Column18", type datetime}, {"Column19", type datetime}, {"Column20", type datetime}, {"Column21", type datetime}, {"Column22", type datetime}, {"Column23", type datetime}, {"Column24", type datetime}, {"Column25", type datetime}, {"Column26", type datetime}, {"Column27", type datetime}, {"Column28", type datetime}, {"Column29", type datetime}, {"Column30", type datetime}, {"Column31", type datetime}, {"Column32", type datetime}, {"Column33", type datetime}, {"Column34", type datetime}}),
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Changed Type", {"RowNo", "AcNo"}, "Attribute", "Value"),
#"Removed Columns" = Table.RemoveColumns(#"Unpivoted Other Columns",{"Attribute"}),
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Value", "EOM Date"}}),
#"Changed Type1" = Table.TransformColumnTypes(#"Renamed Columns",{{"EOM Date", type date}})
in
#"Changed Type1"
- 按 AcNo 然后按日期对结果进行排序:
请注意,以这种方式完成后,第一个日期实际上是 BOM 日期,但如果您将它们格式化为结果中的格式,嗯嗯,它看起来是一样的。如果这是一个问题,事情很容易改变。
如果不希望将第一个月作为 BOM 日期:
- 将公式更改为:
=IF(EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A)-1)<=Table1[@[EndDate]:[EndDate]],EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A)-1),"")
- 执行
Data Get & Transform
时,删除Query GUI编辑器中的StartDate
列,因为这不会影响当时的其他列。