【问题标题】:Compare cell with a previous one in the same column- VBA将单元格与同一列中的前一个单元格进行比较 - VBA
【发布时间】:2022-01-02 17:25:48
【问题描述】:

我在excel中有这样的数据,一栏:

10/15/2021  7:59:42 AM
10/15/2021  7:59:44 AM
10/15/2021  7:59:46 AM
.
.
.
10/16/2021  7:59:42 AM
10/16/2021  7:59:48 AM
10/16/2021  7:59:49 AM

我在 VBA 中使用此代码创建了两列,一列带有日期,一列带有时间:

Sub CommandButton1_Click()
    Dim rng As Range
    Set rng = [A1]
    Set rng = Range(rng, Cells(Rows.Count, rng.Column).End(xlUp))

    rng.Texttocolumns Destination:=[B1], DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, _
    ConsecutiveDelimiter:=False, Tab:=False, _
    Semicolon:=False, Comma:=False, Space:=True, Other:=False, FieldInfo:=Array(Array(1, xlMDYFormat), Array(2, xlMDYFormat), Array(3, xlGeneralFormat)), _
    TrailingMinusNumbers:=True
    
    Columns("C").Delete
    Columns("E").Delete
    Columns("D").Delete
    
End Sub

在那之后,我有两列。 我的目标是有一个包含日期和时间的列,但仅在第一次出现日期时才有日期。 我已经使用 IF 和后来的 CONCAT 使用 excel 完成了此操作。 我复制了第一行,第二行我使用了:

IF(B3=B2,"",B3)

结果是空单元格,然后我将 CONCAT 与包含时间的行一起使用。 我很想在 VBA 中执行此操作,但我不确定如何操作。

【问题讨论】:

  • 您的日期很可能不是文本字符串,而是经过格式化以显示您所见方式的真实日期。 TextToColumns 作用于单元格中的值,而不是格式化显示。但 Excel 将日期存储为十进制数,其中整数部分表示自 1900 年 1 月 1 日以来的天数,小数部分表示一天(或时间)的分数。所以你需要相应地拆分成值的整数部分和小数部分。
  • 您真正想要完成什么?消除重复(相同)的日期?如果是这样,您应该使用单个代码行rng.RemoveDuplicates 1。没有TextTocolumns 部分...
  • 我没有任何重复的数据,我有相同的日期但不同的时间。我用 texttocolumn 将它们分开,所以我可以应用 IF 并仅在第一次出现时获取日期,而在其他单元格中我变空了,所以当我使用 CONCAT 时,我只有第一次有日期 + 时间,而对于其他单元格我有只有时间。我用 if 和 concat 很容易做到这一点,但我想用 VBA 做到这一点
  • @RonRosenfeld TexttoColumns 部分一切正常,我在一列日期,在一列时间内得到我想要的。我之后做的事情很重要,因为我用 IF 和 CONCAT 做,我想用 VBA 做。
  • 总是更快地将两列读入 VBA 数组(参见Arrays and Ranges in VBA),然后循环遍历它,将相应的条目清空;然后将数组写回工作表。

标签: excel vba if-statement


【解决方案1】:

请尝试下一个方法。它将处理初始列,而不是按列拆分。它假定保存日期的列是“A:A”。对于更大的范围,它应该非常快,使用数组并在内存中工作。它将在“B:B”列中返回处理后的数组,从第二行开始(在第一行中我假设标题应该是):

Sub keepFirstDateOnly_Date()
  Dim sh As Worksheet, lastR As Long, arrD, arrFin
  Dim firstD As String, i As Long, j As Long
  
  Set sh = ActiveSheet
  lastR = sh.Range("A" & sh.rows.count).End(xlUp).row
  arrD = sh.Range("A2:A" & lastR).Value2
  ReDim arrFin(1 To UBound(arrD), 1 To 1)
  For i = 1 To UBound(arrD)
     arrFin(i, 1) = Format(arrD(i, 1), "mm/dd/yyyy hh:mm:ss AM/PM")
     Do While DateSerial(Year(arrD(i + j, 1)), month(arrD(i + j, 1)), Day(arrD(i + j, 1))) = _
                              DateSerial(Year(arrD(i, 1)), month(arrD(i, 1)), Day(arrD(i, 1)))
        j = j + 1: If i + j >= UBound(arrD) Then Exit Do
        arrFin(i + j, 1) = Format(TimeValue(CDate(arrD(i + j, 1))), "hh:mm:ss AM/PM")
     Loop
     i = i + j - 1: j = 0
  Next i
  sh.Range("B2").Resize(UBound(arrFin), 1).value = arrFin
End Sub

它仅在要处理的范围被格式化为 As Date 时才有效,如您所述。

请进行测试并发送一些反馈。

如果您喜欢 B:B 中的结果,同样建议将“B2”更改为“A2”,以使其覆盖 A:A 现有内容。

【讨论】:

  • 我测试过,但是这个解决方案只返回我第一次有日期的行,所以代码之后的结果是新列有 4 行,因为我有 4 个不同的日期。但我需要保留每一行,而不是每一行的日期。
  • @Ena 那么,您想保留上面代码显示的内容,但它们最初存在的那一行?
  • 所以我的数据如上图所示,结果我需要的一列结果是:1st row: 10/15/2021 7:59:42 2nd row: 7:59:44 3rd row: 7:59:46 . . . 20th row: 10/16/2021 7:59:42 21st row: 7:59:48 22nd row: 7:59:49 与之前相同的行值,但不是每次都显示日期,只显示当它第一次出现时。
  • 好的。我将使其适应以这种方式返回。但我无法从你的问题中理解你真正需要什么,对不起......
  • 我在新的 excel 中再次尝试,它可以工作。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-15
  • 2013-06-20
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多