CountIf结果为 "0"

问题描述 投票:0回答:1

我的完整代码中有一部分需要帮助。下面的代码应该计算每个月符合定义条件的行。问题是我只得到 "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

enter image description here

成绩单(Wb - 如你所见,在行数表中只显示了零。

enter image description here

wb.Source的例子 - 列H(8)和AD(30)是唯一与行计算相关的列。在下面的例子中,最后一行不应该被计算,因为日期不符合条件(它不是每月的第一天)。

enter image description here

excel vba excel-vba countif
1个回答
1
投票

是的,问题出在你处理日期的方式上。你的数据有真实的日期。他们不是随机数字,而是从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中添加了一个年份。你可以把那个单元格移到任何地方,或者在代码中硬生生地编入一个年份。

你对搜索范围的定义,仅仅是按列来定义是不够的,而且它与你想写入计数的单元格重叠。我已经假设了一个起始行,我的代码找到了每一列的末尾。请大家试一试。


0
投票

在下面的代码中,计数过程被转换为一个函数,将其结果以数组形式返回。这个函数被主程序调用并写入工作表。我没能测试这段代码的全部内容,但上面描述的那部分内容和广告中的一样。

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的单词,我就会遵循现有的大写。

© www.soinside.com 2019 - 2024. All rights reserved.