VBA - Excel Получение одинаковых данных с разных листов на разных позициях - PullRequest
0 голосов
/ 23 января 2019

Я хочу создать макрос, который откроет все книги Excel в папке, прочитает заполненную информацию и сохранит их на листе, который будет представлять мою базу данных.Мне нужно знать ваши предложения и как лучше всего это сделать, чтобы получить быстрый и гибкий результат.

Чтобы помочь вам понять мой вопрос, давайте предположим, что у меня есть 3 шаблона Excel, содержащие Имя,Фамилия и Страна, но на разных позициях, как на этих фотографиях

Шаблон 1 Template1

Шаблон 2 Template2

Шаблон 3 Template3

Исходя из этого, конечный результат, который я хотел бы получитьэто: Result

Пример, который я даю на этих рисунках, действительно очень прост, но он просто помог вам понять, чего я хочу.Теперь я подробно расскажу о реальной необходимости.На самом деле у меня есть 3 шаблона, но каждый из них содержит около 80 полей для сбора данных (не только имя, фамилия и страна).И мне не нужно читать только 3 файла, но я должен прочитать около 200 файлов, помещенных в папку, и каждый из них будет либо template1, либо 2 или 3. В будущем у нас может быть шаблон 4, поэтому мне нужночто-то гибкое.

Я думал об именованных диапазонах, но шаблон 1,2,3 уже существует, и я не могу собрать из 200 пользователей 200 существующих файлов исключений, и перед запуском моего макроса, даваяименованный диапазон до поля 80 в каждом файле.Я могу использовать именованный диапазон, если в будущем это будет шаблон 4, поэтому перед отправкой файлов конечному пользователю, который заполнит Excel, мы назовем диапазоны и отправим его ему, но перед шаблоном 4 я должен исправитьпроблема существующих трех существующих шаблонов.

Я также подумал о чтении данных на основе столбцов и индексов строк, например, я проверяю тип файла, и если я читаю файл шаблона один, я получаю имяиз ячейки (2,3), и если это шаблон 2, я получаю информацию из ячейки (5,6), а если это шаблон 3, я получаю информацию от Cel (9,4), но проблема в том,что мой код совсем не будет гибким.

Я также сказал, что мне может понравиться лист, называемый ссылкой, в котором я определяю позиции каждого поля на основе модели шаблона, например, я говорю, чтоимя для шаблона 1 в позиции 2,3 для шаблона 2, имя для 5,6 и для шаблона 3 это 9,4.Как и на следующем рисунке, и когда я перебираю свои 200 файлов, я проверяю, является ли это шаблон 1, я читаю справочный лист и знаю, что имя будет в этой позиции, то же самое для шаблона 2 и так далее ...Это решение выглядит как предыдущее, но более гибкое, потому что все, что нам нужно изменить, это справочная таблица, если что-то изменится, но мне интересно, будет ли это быстрым или медленным, если для каждого поля мне нужно будет прочитать 2 клеткисправочный лист, чтобы узнать положение.Sheet Reference

Я действительно потерян, потому что мне нужно выбрать лучший способ сделать то, что я хочу, прежде чем начать кодирование, чтобы избежать потери времени.Если кто-то из экспертов поможет мне, расскажет, что лучше, или даст больше идей, чем я думал, я буду очень признателен.

Заранее благодарен любому помощнику

РЕДАКТИРОВАТЬ: @PEH, чтоты думаешь о том, чтобы я сделал свою таблицу поиска такой?enter image description here

РЕДАКТИРОВАТЬ 2: @PEH, это то, что предлагается в последнем комментарии enter image description here

1 Ответ

0 голосов
/ 23 января 2019

Основная идея (помимо циклического просмотра ваших файлов):

  1. Измените данные поиска на следующие:

    enter image description here

  2. Затем прочитайте Cells(1, 6), чтобы получить вашу модель.

    Dim Model As String
    Model = Worksheets("MyTemplate").Cells(1, 6).Value
    
  3. Используйте метод WorksheetFunction.Match , чтобы найтиВаше поле в таблице поиска.

    Dim FieldRow As Long
    FieldRow = Application.WorksheetFunction.Match(Model & "-First name", Worksheets("LookupTable").Range("A:A"), 0)
    
  4. Используйте…

    fRow = Worksheets("LookupTable").Cells(FieldRow, 2)
    fColumn = Worksheets("LookupTable").Cells(FieldRow, 3)
    

    Чтобы получить строку и столбец, где искать это поле в шаблоне.

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

Option Explicit

Public LookupCache As Variant
Public LookupResults As Variant

Public Function ReadField(Ws As Worksheet, FieldName As String) As Variant
    'Here we cache the lookup table. It reads the sheet LookupTable into an 
    'array if the array does not exist yet. If the function runs a second time,
    'the array exists already and is used directly (saves time).
    'Lookup in arrays is much faster than in cells.
    'Caching makes this function about 2 times faster than without.
    If IsEmpty(LookupCache) Or IsEmpty(LookupResults) Then
        With ThisWorkbook.Worksheets("LookupTable")
            Dim LastLookupRow As Long
            LastLookupRow = .Cells(.Rows.Count, "A").End(xlUp).Row
            LookupCache = .Range("A2", "A" & LastLookupRow).Value
            LookupResults = .Range("B2", "C" & LastLookupRow).Value
        End With
    End If

    Dim ModelName As String
    ModelName = Ws.Cells(1, 6).Value

    Dim LookupRow As Long
    On Error Resume Next
    LookupRow = Application.WorksheetFunction.Match(ModelName & "-" & FieldName, LookupCache, 0)
    On Error GoTo 0

    If LookupRow = 0 Then
        'field not found
        ReadField = CVErr(xlErrNA)
        Exit Function
    End If

    Dim fRow As Long, fColumn As Long
    fRow = LookupResults(LookupRow, 1)
    fColumn = LookupResults(LookupRow, 2)

    ReadField = Ws.Cells(fRow, fColumn).Value
End Function

Чтобы вы могли прочитать поле типа

Debug.Print ReadField(MyLoopWorkbook.Worksheets("MyTemplate"), "First name")
'MyLoopWorkbook should be the current workbook in your files loop

Редактировать в соответствии с комментарием…

Если мы добавили новое поле Company в новую модель4, пользователь должен перейти к таблице поиска на листе и добавить Model4-Company в строке 11 со строкой и столбцом, а также в коде, который он должен перейти и добавить ReadField(MyLoopWorkbook.Worksheets("MyNewTemplate"), "Company"), верно?Вот почему я не понимаю, как я могу рассчитывать только на людей, которые не пишут код, чтобы добавить это?Можете ли вы уточнить, пожалуйста, потому что то, что вы сказали, действительно важно.

Если вы сделаете деталь ReadField динамической, вам не нужно и здесь кодировать.Например, если вы хотите получить такую ​​таблицу:

enter image description here

Вы просто добавили бы новый заголовок в столбец 4, называемый как поле, например:Company.И напишите цикл, который проходит по столбцам этой строки заголовка, чтобы собрать все поля.

Sub ReadAllFields()
    Dim wsData As Worksheet
    Set wsData = Worksheets("CollectedData")

    Dim FreeRow As Long 'find next free row in table
    FreeRow = wsData.Cells(wsData.Rows.Count, "A").End(xlUp).Row + 1

    Dim Fields() As Variant 'read headers into array
    Fields = wsData.Range("A1", wsData.Cells(1, wsData.Columns.Count).End(xlToLeft)).Value

    Dim iCol As Long
    For iCol = 1 To UBound(Fields, 2) 'loop through header columns
        wsData.Cells(FreeRow, iCol).Value = ReadField(MyLoopWorkbook.Worksheets("MyNewTemplate"), Fields(1, iCol)) 
        'reads fields dynamically depending on which headers exist in data sheet
    Next iCol
End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...