Как сравнить значения строк нескольких столбцов с одинаковым заголовком на разных листах, даже если эти столбцы находятся только на одном листе?

Ниже приведен код, который мне нужно сравнить значения строк столбцов с одинаковыми заголовками «abc», «def» и «ghi» в ws_checks, предполагая, что эти столбцы находятся как в Sheet1, так и в Sheet2. Как его можно расширить для сравнения нескольких столбцов (а не только 2, может быть любое количество столбцов на 1 листе или на всех листах с 1 по 5), которые имеют один и тот же заголовок столбца?

'''

Dim r, lr, lr1, lr2, col1, col2, lc_checks, nextCol As Long
Dim Rng1, Rng2, Found1, Found2 As Range
Dim foundX As Boolean
Dim header, headerList As Variant

' List of column headers to compare 
headerList = Array("abc", "def", "ghi")

' Loop through each header in the list
For Each header In headerList
    ' Find the column index of the header in both sheets
    On Error Resume Next ' Handle the case where header might not be found
    col1 = Application.Match(header, ws1.Rows(2), 0)
    col2 = Application.Match(header, ws2.Rows(2), 0)
    On Error GoTo 0 
    
   ' Find the last row with data in the columns
    lr1 = ws1.Cells(ws1.Rows.Count, col1).End(xlUp).Row
    lr2 = ws2.Cells(ws2.Rows.Count, col2).End(xlUp).Row
    
    ' Find the next column to paste the next check
    lc_checks = ws_checks.Cells(1, Columns.Count).End(xlToLeft).Column
    nextCol = lc_checks + 1
    
    ' Compare values in the rows of the current column header
    For r = 3 To Application.WorksheetFunction.Min(lr1, lr2)
    
    ws_checks.Cells(1, nextCol).Value = ws1.Cells(2, col1).Value 
        
        If ws1.Cells(r, col1).Value = ws2.Cells(r, col2).Value Then
            ws_checks.Cells(r - 1, nextCol).Value = "Match"
        Else: ws_checks.Cells(r - 1, nextCol).Value = "Mismatch"
     
    Next r

'''

Как вы предлагаете обрабатывать пометку «Совпадение/Несоответствие», когда столбцы сравниваются на нескольких листах, а не только на двух?

Tim Williams 02.08.2024 00:20

К вашему сведению Application.Match не выдает ошибку во время выполнения, если совпадение не найдено, а вместо этого возвращает значение ошибки, поэтому col1 и/или col2 могут оказаться значениями ошибки и привести к сбою следующих строк кода.... Возможно, это связано - вы не можете Dim перечислить переменные, разделенные запятыми, как определенные типы, добавив тип последним в списке — каждой переменной нужен тип.

Tim Williams 02.08.2024 01:45

@TimWilliams Столбцы с одинаковым заголовком должны иметь одинаковые значения во всех своих строках, и мой вопрос заключается в том, как сравнить все эти столбцы, даже если они отображаются на 1 или 4 листах.

grace0726 02.08.2024 15:18

Да, я понимаю это, но если, например, один и тот же столбец существует на 4 листах, но имеет разные значения на этих листах, как его следует пометить? «Соответствовать» только в том случае, если одно и то же значение находится в одной строке на каждом из 4 листов, в противном случае «нет совпадений»? Зачем игнорировать значения в конце одного столбца, если другой столбец короче?

Tim Williams 02.08.2024 17:23

@TimWilliams Верно, было бы хорошо проверить, что они тоже имеют одинаковую длину. Есть ли у вас какие-либо предложения по моему вопросу?

grace0726 02.08.2024 19:48

Да, но вы не ответили на мой вопрос о том, как будет работать пометка, если существует несколько листов с одинаковым именем столбца. Существует ли только один «основной» лист, с которым следует сравнивать другие листы, или следует сравнивать каждую пару листов? Или ? Вам необходимо точно объяснить, что должен делать код, потому что точный процесс, описанный в опубликованном вами коде, не применим.

Tim Williams 02.08.2024 19:57
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
0
6
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуйте это. Комментарии в коде.

Const HEADER_ROW As Long = 2 'header row# on all sheets

Sub CompareColumns()
    Dim cols As Collection, headerList, header, n As Long, i As Long, j As Long
    Dim rng As Range, v, wb As Workbook, wsCheck As Worksheet
    Dim cPos As Long, ok As Boolean, colOK As Boolean
    
    headerList = Array("abc", "def", "ghi") 'column headers to compare
    Set wb = ThisWorkbook
    
    Set wsCheck = ThisWorkbook.Worksheets("ws_checks")
    wsCheck.Cells.Clear
    
    For Each header In headerList             'check each header
        Debug.Print "---Checking:" & header & "---"
        Set cols = CompareRanges(wb, header)  'check all sheets for the header
        If cols.Count > 1 Then                'any sheets to compare?
            colOK = True
            cPos = HeaderPos(wsCheck, header)     'header position on "check "sheet
            ResetFill cols                    'clear previous flags
            For i = 1 To cols(1).Cells.Count  'column length
                ok = True
                v = cols(1)(i)                'read value from first column
                For j = 2 To cols.Count       'check other columns
                    If cols(j).Cells(i).Value <> v Then   'mismatch?
                        For Each rng In cols  'flag all columns at this position
                            rng.Cells(i).Interior.Color = vbRed
                        Next rng
                        ok = False            'row mismatch
                        colOK = False         'column not matched
                        Exit For              'done checking
                    End If
                Next j
                wsCheck.Cells(cols(1)(i).Row, cPos).Value = IIf(ok, "O", "X")
            Next i
            wsCheck.Cells(HEADER_ROW, cPos).Interior.Color = IIf(colOK, vbGreen, vbRed)
        End If
    Next header
End Sub

'Check all sheets in workbook `wb` for the header `hdr` on the configured row
'  Return a collection of all data columns below found headers, sized to the max length
'   of all of the returned ranges
Function CompareRanges(wb As Workbook, hdr) As Collection
    Dim ws As Worksheet, col As New Collection, maxRow As Long, lr As Long
    Dim rng As Range, m, i As Long, c As Range, lc As Long
    For Each ws In wb.Worksheets
        lc = ws.Cells(HEADER_ROW, ws.Columns.count).End(xlToLeft).Column
        For Each c In ws.Cells(HEADER_ROW, 1).Resize(1, lc).Cells
            If c.Value = hdr Then
                col.Add ws.Cells(HEADER_ROW + 1, c.Column)
                lr = ws.Cells(Rows.count, c.Column).End(xlUp).Row
                If lr > maxRow Then maxRow = lr
            End If
        Next c
    Next ws
    Set CompareRanges = New Collection
    If col.count = 0 Then Exit Function
    For Each rng In col  'make all columns same size as the longest one
        CompareRanges.Add rng.Resize(maxRow - HEADER_ROW)
    Next rng
End Function

'Clear any fill from a collection of ranges
Sub ResetFill(col As Collection)
    Dim rng As Range
    For Each rng In col
        Debug.Print rng.Parent.name, rng.Address
        rng.Interior.ColorIndex = xlNone
    Next rng
End Sub

'Return the column number for header `hdr` on sheet `ws`
'  Add the header if not found
Function HeaderPos(ws As Worksheet, hdr) As Long
    Dim m
    m = Application.Match(hdr, ws.Rows(HEADER_ROW), 0)
    If IsError(m) Then
        m = ws.Cells(HEADER_ROW, Columns.Count).End(xlToLeft).Column
        If Len(ws.Cells(HEADER_ROW, m)) > 0 Then m = m + 1
        ws.Cells(HEADER_ROW, m).Value = hdr
    End If
    HeaderPos = CLng(m)
End Function

Большое спасибо, что уделили время приведенному выше коду. Думаю, теперь я понял ваш первоначальный вопрос. Есть лист (ws_checks) для вставки заголовков этих столбцов, и если значения всех столбцов с заголовком «abc» совпадают в строке 7, ws_checks с заголовком «abc» будет иметь «O». в строке 7, если какое-либо значение этих столбцов не совпадает со строкой 15, в строке 15 ws_checks появляется «X». А заголовок «abc» в ws_checks имеет зеленый или красный цвет в зависимости от того, совпадают ли все значения строк.

grace0726 05.08.2024 16:07

См. правки выше

Tim Williams 05.08.2024 18:11

Привет, Тим, можешь ли ты указать мне, как вместо этого вставить галочки, начиная со строки 1?

grace0726 06.08.2024 17:09

Когда закончите, вы можете просто удалить строку 1 из ws_checks.

Tim Williams 06.08.2024 17:25

Спасибо, это сработало. Теперь у меня возникла еще одна проблема: если я удалю столбец с заголовком «abc» на листе Sheet1, чтобы он появлялся дважды только на листе Sheet2, ваш код не добавит «abc» на листе проверки. Кроме того, если в книге есть 3 столбца с заголовком «abc» и в строке есть несоответствие, только ячейки первых двух столбцов будут окрашены в красный цвет.

grace0726 06.08.2024 19:00

Возможно, это проблема в Excel; ResetFill, похоже, не работает.

grace0726 06.08.2024 19:19

В вашем вопросе ничего не говорится о повторении столбца на одном и том же листе, поэтому мой код с этим не справляется. Вы можете попробовать изменить CompareRanges, чтобы обнаружить заголовок, если он встречается более одного раза. Я не знаю, в чем проблема с ResetFill — как именно это выглядит?

Tim Williams 06.08.2024 19:33

Ну, в моем первоначальном вопросе я просил «любое количество столбцов на 1 листе». ResetFill только что сработал, я не уверен, что случилось.

grace0726 06.08.2024 19:52

Хорошо, честно — см. изменения в CompareRanges выше. Теперь должно фиксироваться >1 экземпляр любого столбца на листе.

Tim Williams 06.08.2024 20:13

Другие вопросы по теме