【问题标题】:Expand Start Date to End Date with Series of EOMONTHs使用一系列 EOMONTH 将开始日期扩展到结束日期
【发布时间】:2017-12-28 15:14:07
【问题描述】:

我有一个包含 ids 的数据表,其中的开始日期和结束日期都关联。

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

我需要扩展(即取消透视)此表,以便在每个 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$2, D$2, "m"), B$2, TEXT(,))
'in G2
=IF(ROW(1:1)-1<DATEDIF(C$2, D$2, "m"), EOMONTH(C$2, 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$2, " & m - 1 & ")"
        Next m
    End With

同样,这一次只扩展一行。

如何循环遍历将每个系列堆叠成一列的行?欢迎对我的公式或代码进行调整的任何建议。

【问题讨论】:

  • 我认为原件被删除了?
  • original 因基本上没有表现出原创性而被关闭。但是,我有一个解决方案在等待,这似乎是一个有趣的问题,所以我重新发布了;希望有一个更好的问题。正如我过去所做的那样,我对所有新答案持开放态度。一个公式或 unpivot 方法会很高兴看到。
  • 如果我明天有时间休息,今天就建一个棚子。刚进来喝点水降温。

标签: excel excel-formula datediff unpivot vba


【解决方案1】:

只是因为您似乎在征求多个选项,这里是一个没有 VBA 的选项:

  • 使用公式将表格向右展开(在此处使用结构化引用):

=IF(EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A))<Table1[@[EndDate]:[EndDate]],EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A)),"")

  • 使用Power QueryData Get &amp; 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 和 Date 对结果进行排序:

请注意,以这种方式完成时,第一个日期实际上是 BOM 日期,但如果您按照结果中的格式设置它们,嗯,yy,它看起来是一样的。如果这是一个问题,事情很容易改变。

如果不希望将第一个月作为 BOM 日期:

  • 将公式更改为:

=IF(EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A)-1)<=Table1[@[EndDate]:[EndDate]],EOMONTH(Table1[@[StartDate]:[StartDate]],COLUMNS($A:A)-1),"")

  • 执行Data Get &amp; Transform时,删除查询GUI编辑器中的StartDate列,此时不会影响其他列。

【讨论】:

    【解决方案2】:

    尝试将其作为嵌套的 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 单元格编号。

    【讨论】:

    • 通过将日期设置为零(而不是选择下个月的第一天并从结果日期数中减去 1 :-) 来欣赏您的“EOMONTH 生成器”的想法和简洁性。
    猜你喜欢
    • 2023-03-17
    • 2015-10-07
    • 1970-01-01
    • 2021-07-25
    • 2022-01-23
    • 1970-01-01
    • 2012-08-19
    • 2021-08-22
    • 2020-10-05
    相关资源
    最近更新 更多