我的完整代码中有一部分需要帮助。下面的代码应该计算每个月符合定义条件的行。问题是我只得到 "0 "的结果。我不知道为什么?是不是因为我的日期格式?我的源wb包含的日期格式是 "01.01.2019"。
代码也应该只计算任何月份的第一条的行。意思是:01.01., 01.02.,01.03.等等。
我的主工作簿(wb)有一个带文件浏览器功能的用户表单,我可以选择我的源工作簿(wbSource),并在上面应用宏。如下面的完整代码所示,我的主工作簿(wb)有一个带有文件浏览器功能的用户表单,我可以选择我的源工作簿(wbSource)并对其应用宏。
希望得到任何帮助。
Dim x As Long
For x = 1 To 12
ws.Cells(8, 1 + x) = _
Application.WorksheetFunction.CountIfs(wsSource.Columns(8), Format(x, "00") & "." & MonthName(x), _
wsSource.Columns(30), "<=" & 50)
ws.Cells(9, 1 + x) = _
Application.WorksheetFunction.CountIfs(wsSource.Columns(8), Format(x, "00") & "." & MonthName(x), _
wsSource.Columns(30), ">" & 50, wsSource.Columns(30), "<=" & 100)
ws.Cells(10, 1 + x) = _
Application.WorksheetFunction.CountIfs(wsSource.Columns(8), Format(x, "00") & "." & MonthName(x), _
wsSource.Columns(30), ">" & 100)
Next x
完整的代码
Private Sub CommandButton2_Click() ' update averages
Const YEAR = 2019
' open source workbook
Dim fname As String, wbSource As Workbook, wsSource As Worksheet
fname = Me.TextBox1.Text
If Len(fname) = 0 Then
MsgBox "No file selected", vbCritical, "Error"
Exit Sub
End If
Set wbSource = Workbooks.Open(fname, False, True) ' no link update, read only
Set wsSource = wbSource.Sheets("Sheet1") ' change to suit
Dim wb As Workbook, ws As Worksheet
Set wb = ThisWorkbook
Set ws = wb.Sheets("Table 2") '
' scan down source workbook calc average
Dim iRow As Long, lastRow As Long
Dim sMth As String, iMth As Long
Dim count(12) As Long, sum(12) As Long
lastRow = wsSource.Cells(Rows.count, 1).End(xlUp).Row
For iRow = 1 To lastRow
If IsDate(wsSource.Cells(iRow, 8)) _
And IsNumeric(wsSource.Cells(iRow, 30)) Then
iMth = Month(wsSource.Cells(iRow, 8)) ' col H
sum(iMth) = sum(iMth) + wsSource.Cells(iRow, 30) ' Col AD
count(iMth) = count(iMth) + 1 '
End If
Next
' counting the rows
Dim x As Long
For x = 1 To 12
ws.Cells(8, 1 + x) = _
Application.WorksheetFunction.CountIfs(wsSource.Columns(8), Format(x, "00") & "." & MonthName(x), _
wsSource.Columns(30), "<=" & 50)
ws.Cells(9, 1 + x) = _
Application.WorksheetFunction.CountIfs(wsSource.Columns(8), Format(x, "00") & "." & MonthName(x), _
wsSource.Columns(30), ">" & 50, wsSource.Columns(30), "<=" & 100)
ws.Cells(10, 1 + x) = _
Application.WorksheetFunction.CountIfs(wsSource.Columns(8), Format(x, "00") & "." & MonthName(x), _
wsSource.Columns(30), ">" & 100)
Next x
' close source worbook no save
wbSource.Close False
' update Table 2 with averages
With ws.Range("A3")
For iMth = 1 To 12
.Offset(0, iMth - 1) = MonthName(iMth) & " " & YEAR
If count(iMth) > 0 Then
.Offset(1, iMth - 1) = sum(iMth) / count(iMth)
.Offset(1, iMth - 1).NumberFormat = "0.0"
End If
Next
End With
Dim msg As String
msg = iRow - 1 & " rows scanned in " & TextBox1.Text
MsgBox msg, vbInformation, "Table 2 updated"
End Sub
成绩单(Wb - 如你所见,在行数表中只显示了零。
wb.Source的例子 - 列H(8)和AD(30)是唯一与行计算相关的列。在下面的例子中,最后一行不应该被计算,因为日期不符合条件(它不是每月的第一天)。
是的,问题出在你处理日期的方式上。你的数据有真实的日期。他们不是随机数字,而是从1900年1月1日开始的天数。它们唯一地识别了过去120年的每一天,系统也将继续识别未来120年的每一天。我相信下面的代码或多或少可以做到你想做的事情。
Sub WriteCountIf()
' 025
' The YearCell must contain a year number like 2019.
Const YearCell As String = "A1" 'change to suit
Dim DateRng As Range ' the range to search for dates in
Dim DaysRng As Range ' the range to search for days in
Dim StartDate As Date ' first day to include in count
Dim EndDate As Date ' last day to include in count
Dim C As Long ' the column to write to (= month)
With ActiveSheet ' better to define the sheet by name
' make sure your result range doesn't overlap the search ranges
Set DateRng = .Range(.Cells(11, 8), .Cells(.Rows.Count, 8).End(xlUp))
Set DaysRng = .Range(.Cells(11, 30), .Cells(.Rows.Count, 30).End(xlUp))
For C = 1 To 12
StartDate = DateSerial(.Range(YearCell).Value, C, 1)
EndDate = DateSerial(Year(StartDate), C + 1, 0)
.Cells(8, 1 + C).Value = Application.WorksheetFunction. _
CountIfs(DateRng, ">=" & StartDate, _
DateRng, "<=" & EndDate, _
DaysRng, "<=" & 50)
.Cells(9, 1 + C).Value = Application.WorksheetFunction. _
CountIfs(DateRng, ">=" & StartDate, _
DateRng, "<=" & EndDate, _
DaysRng, ">" & 50, _
DaysRng, "<=" & 100)
.Cells(10, 1 + C).Value = Application.WorksheetFunction. _
CountIfs(DateRng, ">=" & StartDate, _
DateRng, "<=" & EndDate, _
DaysRng, ">" & 100)
Next C
End With
End Sub
你的数据似乎只显示了日和月。这是一个显示(单元格格式)的问题。基本的日期包括年份。因此,当你搜索它们时,你需要一个年份。我已经在A1中添加了一个年份。你可以把那个单元格移到任何地方,或者在代码中硬生生地编入一个年份。
你对搜索范围的定义,仅仅是按列来定义是不够的,而且它与你想写入计数的单元格重叠。我已经假设了一个起始行,我的代码找到了每一列的末尾。请大家试一试。
在下面的代码中,计数过程被转换为一个函数,将其结果以数组形式返回。这个函数被主程序调用并写入工作表。我没能测试这段代码的全部内容,但上面描述的那部分内容和广告中的一样。
Private Sub CommandButton2_Click() ' update averages
' "Year" is the name of a VBA function.
' To use the same word here as a variable name is asking for trouble.
Const Year As Integer = 2019
Dim wbSource As Workbook, wsSource As Worksheet
Dim Wb As Workbook, Ws As Worksheet
Dim fname As String
fname = Me.TextBox1.Text
If Len(fname) = 0 Then
MsgBox "No file selected", vbCritical, "Error"
Exit Sub
End If
Set Wb = ThisWorkbook
Set Ws = Wb.Sheets("Table 2") '
' open source workbook
Set wbSource = Workbooks.Open(fname, False, True) ' no link update, read only
Set wsSource = wbSource.Sheets("Sheet1") ' change to suit
Dim iRow As Long, lastRow As Long
Dim sMth As String, iMth As Long
Dim count(12) As Long, sum(12) As Long ' Confusing: Count is a VBA method
' scan down source workbook calc average
' observe how .Rows.count is written with lower case c
' because of your declaration of "count" in that way
lastRow = wsSource.Cells(wsSource.Rows.count, 1).End(xlUp).Row
For iRow = 1 To lastRow
If IsDate(wsSource.Cells(iRow, 8)) And _
IsNumeric(wsSource.Cells(iRow, 30)) Then
iMth = Month(wsSource.Cells(iRow, 8)) ' col H
sum(iMth) = sum(iMth) + wsSource.Cells(iRow, 30) ' Col AD
count(iMth) = count(iMth) + 1
End If
Next
' counting the rows
Ws.Cells(8, 2).Resize(3, 12).Value = RowsCount(Year, wsSource)
' close source worbook no save
wbSource.Close False
' update Table 2 with averages
With Ws.Range("A3")
For iMth = 1 To 12
.Offset(0, iMth - 1) = MonthName(iMth) & " " & Year
If count(iMth) > 0 Then
.Offset(1, iMth - 1) = sum(iMth) / count(iMth)
.Offset(1, iMth - 1).NumberFormat = "0.0"
End If
Next
End With
Dim msg As String
msg = iRow - 1 & " rows scanned in " & TextBox1.Text
MsgBox msg, vbInformation, "Table 2 updated"
End Sub
Private Function RowsCount(ByVal RefYear As Integer, _
Ws As Worksheet) As Variant
' 025
Dim Fun As Variant ' Function return value
Dim DateRng As Range ' the range to search for dates in
Dim DaysRng As Range ' the range to search for days in
Dim StartDate As Date ' first day to include in count
Dim EndDate As Date ' last day to include in count
Dim C As Long ' the column to write to (= month)
With Ws
' make sure your result range doesn't overlap the search ranges
Set DateRng = .Range(.Cells(11, 8), .Cells(.Rows.count, 8).End(xlUp))
Set DaysRng = .Range(.Cells(11, 30), .Cells(.Rows.count, 30).End(xlUp))
End With
ReDim Fun(1 To 3, 1 To 12)
For C = 1 To 12
StartDate = DateSerial(RefYear, C, 1)
EndDate = DateSerial(Year(StartDate), C + 1, 0)
Fun(1, C) = Application.WorksheetFunction. _
CountIfs(DateRng, ">=" & StartDate, _
DateRng, "<=" & EndDate, _
DaysRng, "<=" & 50)
Fun(2, C) = Application.WorksheetFunction. _
CountIfs(DateRng, ">=" & StartDate, _
DateRng, "<=" & EndDate, _
DaysRng, ">" & 50, _
DaysRng, "<=" & 100)
Fun(3, C) = Application.WorksheetFunction. _
CountIfs(DateRng, ">=" & StartDate, _
DateRng, "<=" & EndDate, _
DaysRng, ">" & 100)
Next C
RowsCount = Fun
End Function
在VBA中,大写是非常重要的。就像你使用的例子一样 Count
字演示VBA会尽量适应你的风格。因此,如果你没有系统,你会破坏VBA的。我遵循的理论是在所有变量名上使用大写和小写。然后我只用小写字母来输入。VBA会纠正我的输入,这就像一个拼写检查器,有助于避免错别字。虽然有一些例外,但这是我遵循的一般规则。
变量名的选择也是如此。一般来说,我避免使用VBA使用的单词。这样可以防止我的混淆(不要在意VBA)。但如果我真的使用了VBA的单词,我就会遵循现有的大写。