Подсчитайте, если для excel VBA, а результаты печати в другом диапазоне

У меня есть список из примерно 12 000 строк с номерами проектов, менеджерами по работе с клиентами, датой создания, статусом ... и т. Д. В настоящее время я делаю отчеты каждые 2 недели в виде сводных таблиц, а затем составляю из них графики. Я знаю, что это можно автоматизировать, поскольку я исключил сводные таблицы и воспроизвел результат с помощью counttifs. Теперь я хочу иметь возможность делать то же самое с VBA, до такой степени, что пользователь может перейти в электронную таблицу, нажать кнопку и отобразить самые свежие данные. Для начала я хочу немного изучить counttif в vba.

Допустим, таблица выглядит так

 A          |         B       |    C
proj.Number   Account Manager   Status
   123            Person 1       Won
   234            Person 2       Lost
   345            Person 3       Quoted

В настоящее время это мой код, который отлично работает для counttif, но без цикла ... и я знаю, что это можно как-то сделать

 Dim PersonOne as Range
    Set PersonOne = Range("E2")
 Dim PersonTwo as Range
    Set PersonTwo = Range("E3") 
 Dim PersonThree as Range
    Set PersonThree = Range("E4")

        Range("D2") = "Person 1"
        Range("D3") = "Person 2"
        Range("D4") = "Person 3"

PersonOne = (WorksheetFunction.CountIf(Range("B2", Range("B2").End(xlDown)), "Person 1"))   
PersonTwo = (WorksheetFunction.CountIf(Range("B2", Range("B2").End(xlDown)), "Person 2"))  
PersonThree = (WorksheetFunction.CountIf(Range("B2", Range("B2").End(xlDown)), "Person 3")) 

Как мне автоматизировать это до такой степени, что мне даже не нужно писать имена людей (часть, где я говорю диапазон (d2) = какой-то человек. Могу ли я иметь код, который ищет все возможные уникальные имена, помещает их в определенном диапазоне электронной таблицы, а затем подсчитать, сколько раз это имя встречается в данном диапазоне?

Спасибо


person Damjan    schedule 28.04.2017    source источник
comment
какая-либо причина не использовать сводную таблицу и сводную диаграмму? support.office.com/ en-us / article /   -  person Slai    schedule 28.04.2017
comment
Отчеты пишу только я, а их только просматривают около 40 человек. Если бы я мог сделать это доступным для всех в любое время (без построения сводных диаграмм и диаграмм), это было бы проще для всех. И мне нравится возиться с такими вещами, просто я не слишком хорош в этом, хотя у меня есть базовое представление о том, что должен делать код. Мне трудно работать с петлями ... вот почему я здесь   -  person Damjan    schedule 28.04.2017
comment
Что вы делаете с данными после подсчета? Вы можете создать массив, чтобы собрать все имена, а затем просто пропустить его. В этом вопросе есть функция в первом ответе, которая проверяет, массив уже содержит строку. Я могу все это записать в ответ, если понадобится.   -  person BerticusMaximus    schedule 28.04.2017
comment
Обычно я просто делаю из него сводные таблицы (столбцов больше, но не относительно заданного мной вопроса). Затем я делаю сводные диаграммы, которые показывают определенные данные. Но прямо здесь я просто хочу знать, как иметь все имена в определенных ячейках, без того, чтобы я вручную вводил имена в код. Например, цикл проходит через столбец B, находит 5 или 6 имен и помещает каждое имя в определенную ячейку (скажем, A1: A6 в другой электронной таблице, а в B1: B6 помещает количество вхождений). Если я пойму, как это сделать, я думаю, что смогу разобраться с остальными вещами.   -  person Damjan    schedule 28.04.2017
comment
Просто установите диапазон данных сводной таблицы до последней строки листа. Игнорируйте пробелы. И нажимайте RefreshAll на вкладке Data каждый раз, когда поступают новые данные.   -  person M--    schedule 28.04.2017
comment
Будет ли это работать, если источником данных являются динамические данные, поступающие из CRM?   -  person Damjan    schedule 28.04.2017
comment
Пока эти данные находятся в книге (в конце, независимо от того, как они были импортированы), вы можете просто обновить их, и ... excel сделает свое дело.   -  person M--    schedule 28.04.2017
comment
Ладно, достаточно честно. Примечание: можно ли сделать то, что я просил? И я подумал об этом, потому что до сих пор у меня нет подключения для импорта CRM (но я планирую попросить его), поэтому каждый раз мне приходится экспортировать данные и начинать с нуля. Теперь, когда я проделал это с формулами, я просто копирую и вставляю данные, на которые ссылаются формулы, и те же графики создаются в другой электронной таблице. Вот почему я подумал о VBA, чтобы люди не возились с электронной таблицей, где формулы   -  person Damjan    schedule 28.04.2017
comment
Вы можете автоматизировать импорт данных, и в конце вы можете просто сказать ActiveWorkbook.RefreshAll, и он обновит сводную таблицу. Также вы можете разблокировать все ячейки, заблокировать те, с которыми пользователи не должны вмешиваться, и защитить лист.   -  person M--    schedule 28.04.2017
comment
И еще одно: избегайте написания кода, который уже можно сделать в Excel (или в любом другом программном обеспечении). Это будет медленнее, а иногда и неправильно, и, конечно же, отнимет много времени.   -  person M--    schedule 28.04.2017


Ответы (3)


Приведенный ниже код и функция должны делать то, что вам нужно. Хотя в настоящее время он печатается в столбцы D и E на той же странице, но вы можете легко изменить это, если хотите в другом месте.

Sub CountIF()

    Dim wbk As Workbook
    Dim ws As Worksheet
    Dim myNames() As String
    Dim lRow As Long, x As Long
    Dim Cell As Range
    Dim Test As Boolean

    Set wbk = Workbooks("Book1.xlsm") 'Change this to your workbook name
    Set ws = wbk.Worksheets("Sheet1") 'Change this to your worksheet name

    ReDim myNames(0 To 0) As String

    With ws
        lRow = .Range("B" & .Rows.Count).End(xlUp).Row
        'Loop through Column B and populate array
        For Each Cell In .Range(.Cells(2, "B"), .Cells(lRow, "B"))
            'Check if Name is already in array
            Test = IsInArray(Cell.Value, myNames) > -1
            If Test = False Then
                'Insert name into array
                myNames(UBound(myNames)) = Cell.Value
                ReDim Preserve myNames(0 To UBound(myNames) + 1) As String
            End If
        Next Cell

        ReDim Preserve myNames(0 To UBound(myNames) - 1) As String
        'Print title in D and value in E
        For x = LBound(myNames) To UBound(myNames)
            'Use x + 1 because our array starts at 0
            .Cells(x + 1, "D").Value = myNames(x)
            .Cells(x + 1, "E").Value = WorksheetFunction.CountIF(.Range(.Cells(2, "B"), .Cells(lRow, "B")), myNames(x))
        Next x
    End With

    Erase myNames

End Sub

Код использует эту функцию, поэтому обязательно включите ее.

Function IsInArray(stringToBeFound As String, arr As Variant) As Long
'http://stackoverflow.com/questions/10951687/how-to-search-for-string-in-an-array
'Boolean = (IsInArray(StringToFind, ArrayToSearch) > -1)
    Dim i As Long
    ' default return value if value not found in array
    IsInArray = -1

    For i = LBound(arr) To UBound(arr)
        If StrComp(stringToBeFound, arr(i), vbTextCompare) = 0 Then
            IsInArray = i
            Exit For
        End If
    Next i
End Function
person BerticusMaximus    schedule 28.04.2017

Вот как вы можете применить его только с помощью сводной таблицы:

Сначала: вставьте сводную таблицу / диаграмму

Вставьте сводную таблицу со всеми нужными столбцами:

введите описание изображения здесь

Во-вторых: пустые фильтры

Затем вы можете добавить желаемое поле в сводную таблицу. Добавьте один из столбцов в качестве фильтра, чтобы игнорировать пробелы:

введите описание изображения здесь

Третье: добавить данные

Позже вы можете добавить данные внизу своей таблицы:

введите описание изображения здесь

Четвертое: обновить

Обновите книгу:

введите описание изображения здесь

И все готово:

введите описание изображения здесь

person M--    schedule 28.04.2017
comment
Я знаю, как использовать сводные таблицы и обновлять их ... но вопрос, который я задал, не касается сводных таблиц ... Я стараюсь держаться от них подальше. То, что вы предоставили, не является ответом на мой вопрос - person Damjan; 28.04.2017
comment
@Damjan Не обижайся. Я не имею в виду, что вы не знаете. У других людей возникнет аналогичный вопрос, и они воспользуются им. Опять же, для этой задачи вам не нужен vba. Но если вы настаиваете на его использовании, напишите код и поделитесь им с нами, и мы будем рады помочь вам, если вы столкнулись с ошибкой. - person M--; 28.04.2017
comment
Спасибо за помощь. Я не обиделась ... Я просто расстроена ... извините за это. Может ли код записать все имена в ячейки A1: A3 в другой электронной таблице (при условии, что этот список был длинным, в нем было бы более трех имен и были бы дубликаты, но мне нужно только одно из каждого имени), а рядом с ним в столбец B, он покажет количество вхождений. Это все, что я прошу - person Damjan; 28.04.2017

Немного поздно, но если вы запишете макрос Data> Consolidate, вы получите что-то вроде:

Range("E1").Consolidate Sources:=Range("B:C").Address(, , xlR1C1, 1), Function:=xlCount, _
                        TopRow:=True, LeftColumn:=True, CreateLinks:=False

введите здесь описание изображения

person Slai    schedule 01.05.2017