Ниже приведен код, который мне нужно сравнить значения строк столбцов с одинаковыми заголовками «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
'''
К вашему сведению Application.Match
не выдает ошибку во время выполнения, если совпадение не найдено, а вместо этого возвращает значение ошибки, поэтому col1
и/или col2
могут оказаться значениями ошибки и привести к сбою следующих строк кода.... Возможно, это связано - вы не можете Dim
перечислить переменные, разделенные запятыми, как определенные типы, добавив тип последним в списке — каждой переменной нужен тип.
@TimWilliams Столбцы с одинаковым заголовком должны иметь одинаковые значения во всех своих строках, и мой вопрос заключается в том, как сравнить все эти столбцы, даже если они отображаются на 1 или 4 листах.
Да, я понимаю это, но если, например, один и тот же столбец существует на 4 листах, но имеет разные значения на этих листах, как его следует пометить? «Соответствовать» только в том случае, если одно и то же значение находится в одной строке на каждом из 4 листов, в противном случае «нет совпадений»? Зачем игнорировать значения в конце одного столбца, если другой столбец короче?
@TimWilliams Верно, было бы хорошо проверить, что они тоже имеют одинаковую длину. Есть ли у вас какие-либо предложения по моему вопросу?
Да, но вы не ответили на мой вопрос о том, как будет работать пометка, если существует несколько листов с одинаковым именем столбца. Существует ли только один «основной» лист, с которым следует сравнивать другие листы, или следует сравнивать каждую пару листов? Или ? Вам необходимо точно объяснить, что должен делать код, потому что точный процесс, описанный в опубликованном вами коде, не применим.
Попробуйте это. Комментарии в коде.
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 имеет зеленый или красный цвет в зависимости от того, совпадают ли все значения строк.
См. правки выше
Привет, Тим, можешь ли ты указать мне, как вместо этого вставить галочки, начиная со строки 1?
Когда закончите, вы можете просто удалить строку 1 из ws_checks.
Спасибо, это сработало. Теперь у меня возникла еще одна проблема: если я удалю столбец с заголовком «abc» на листе Sheet1, чтобы он появлялся дважды только на листе Sheet2, ваш код не добавит «abc» на листе проверки. Кроме того, если в книге есть 3 столбца с заголовком «abc» и в строке есть несоответствие, только ячейки первых двух столбцов будут окрашены в красный цвет.
Возможно, это проблема в Excel; ResetFill, похоже, не работает.
В вашем вопросе ничего не говорится о повторении столбца на одном и том же листе, поэтому мой код с этим не справляется. Вы можете попробовать изменить CompareRanges
, чтобы обнаружить заголовок, если он встречается более одного раза. Я не знаю, в чем проблема с ResetFill
— как именно это выглядит?
Ну, в моем первоначальном вопросе я просил «любое количество столбцов на 1 листе». ResetFill только что сработал, я не уверен, что случилось.
Хорошо, честно — см. изменения в CompareRanges
выше. Теперь должно фиксироваться >1 экземпляр любого столбца на листе.
Как вы предлагаете обрабатывать пометку «Совпадение/Несоответствие», когда столбцы сравниваются на нескольких листах, а не только на двух?