엑셀 자동 필터는 병합된 셀을 제대로 다루지 못합니다. 여러 행을 병합해서 한 항목을 표시한 표에 필터를 걸면, 병합 영역의 첫 행만 조건에 걸리고 나머지 행은 따로 놀아서 표가 깨져 보입니다. 그래서 매크로로 "찾은 셀이 속한 병합 영역의 행 전체"를 숨기는 방법을 만들어 봤습니다. 결론부터 말하면 동작은 하는데 데이터가 많으면 느려서 쓰기 어렵습니다.
테스트 데이터는 1만 건입니다.

검색어가 들어간 행을 숨기는 매크로
Sub program1472_com()
Cells.EntireRow.Hidden = False
DoEvents
Application.ScreenUpdating = False
Dim C As Range, value As String, v As Variant
Dim strAddr As String, rng As Range
Set rng = ActiveSheet.UsedRange
value = InputBox("검색할 텍스트를 ,로 분리해서 넣으세요")
For Each v In Split(value, ",")
Set C = rng.Find(what:=v, lookat:=xlPart) '// XlLookAt 상수 xlWhole(전체 일치) 또는 xlPart(부분 일치)
If Not C Is Nothing Then
strAddr = C.Address
Do
C.MergeArea.EntireRow.Hidden = True
Set C = rng.FindNext(C)
Loop While Not C Is Nothing And strAddr <> C.Address
End If
Next
MsgBox "완료!!"
End Sub
먼저 모든 행 숨김을 풀어 이전 결과를 지우고, 입력받은 문자열을 쉼표로 나눠 검색어마다 반복합니다. Find 로 첫 번째 셀을 찾은 뒤 그 주소를 기억해 두고, FindNext 로 다음 셀을 계속 찾다가 처음 주소로 되돌아오면 한 바퀴를 다 돈 것이니 멈춥니다. 찾은 셀마다 MergeArea.EntireRow 를 숨기기 때문에, 병합 셀 안의 글자에 걸려도 병합된 행들이 한꺼번에 숨겨집니다. 병합되지 않은 셀이면 MergeArea 는 그 셀 자신이라 그 행 하나만 숨겨집니다.
lookat:=xlPart 라 검색어가 셀 값의 일부에만 들어 있어도 찾습니다. 정확히 일치하는 셀만 찾으려면 xlWhole 로 바꾸면 됩니다.
"02,011,김" 으로 실행한 결과


결과는 맞게 나오지만 필터에 비하면 시간이 어마어마하게 걸렸습니다.

왜 느린가, 그리고 반대 작업
느린 이유는 찾을 때마다 행을 하나씩 숨기기 때문입니다. 행 숨김은 시트 레이아웃을 다시 계산하는 작업이라, 숨길 행이 수천 개면 그만큼 레이아웃 갱신이 반복됩니다. ScreenUpdating 을 꺼도 이 비용은 그대로 남습니다. 개선한다면 찾은 영역을 Union 으로 하나의 Range 에 모아 두었다가 마지막에 EntireRow.Hidden = True 를 한 번만 실행하는 쪽이 낫습니다.
이 예제는 검색된 행을 숨기는 방향입니다. 필터처럼 검색된 행만 보이게 하려면 더 오래 걸립니다. 찾은 셀을 전부 기억해 뒀다가, 그 외의 행을 숨기는 반대 작업을 해야 하니까요. 이때도 전체 행을 숨긴 뒤 찾은 행만 한 번에 보이게 하는 순서로 짜야 그나마 시간이 줄어듭니다.
반복 조건 Not C Is Nothing And strAddr <> C.Address 도 주의할 곳입니다. VBA 의 And 는 앞 조건이 거짓이어도 뒤 조건까지 계산하기 때문에, C 가 Nothing 이 되는 상황이면 C.Address 에서 오류가 납니다. 고쳐 쓸 때는 루프 안에서 If C Is Nothing Then Exit Do 로 먼저 빠져나오게 하는 편이 안전합니다.
Union 으로 모아서 한 번에 숨기는 형태
위에서 말한 개선 방향과 루프 조건 수정을 합친 코드입니다. 찾은 병합 영역을 hideRng 에 계속 모아 두고, 검색이 다 끝난 다음 한 번만 숨깁니다. 검색어 앞뒤 공백은 Trim 으로 떼고, 쉼표가 연달아 들어가 생긴 빈 검색어는 건너뜁니다.
Sub HideFoundRows()
Dim C As Range, hideRng As Range, rng As Range
Dim v As Variant, strAddr As String, value As String
Cells.EntireRow.Hidden = False
Set rng = ActiveSheet.UsedRange
value = InputBox("검색할 텍스트를 ,로 분리해서 넣으세요")
If Len(value) = 0 Then Exit Sub
Application.ScreenUpdating = False
For Each v In Split(value, ",")
If Len(Trim(v)) Then
Set C = rng.Find(What:=Trim(v), LookAt:=xlPart)
If Not C Is Nothing Then
strAddr = C.Address
Do
If hideRng Is Nothing Then
Set hideRng = C.MergeArea
Else
Set hideRng = Union(hideRng, C.MergeArea)
End If
Set C = rng.FindNext(C)
If C Is Nothing Then Exit Do
Loop While C.Address <> strAddr
End If
End If
Next
If Not hideRng Is Nothing Then hideRng.EntireRow.Hidden = True
Application.ScreenUpdating = True
End Sub
이 방식도 만능은 아닙니다. 서로 떨어진 영역이 수천 개 쌓이면 Union 자체가 점점 느려지기 때문에, 데이터 양에 따라서는 기대만큼 빨라지지 않을 수 있습니다. 같은 1만 건 데이터에서 직접 시간을 재 보고 원래 코드와 비교해 보세요. 원래 코드는 InputBox 에서 취소를 눌러도 빈 문자열로 그대로 진행했는데, 여기서는 바로 빠져나오게 했습니다.
Find 를 쓸 때 하나 더 알아 둘 점이 있습니다. LookIn, LookAt, MatchCase 같은 설정은 호출할 때 지정하지 않으면 직전에 쓴 값을 그대로 이어받습니다. 엑셀의 찾기 대화 상자에서 바꾼 설정도 포함됩니다. 그래서 같은 매크로가 어떤 때는 찾고 어떤 때는 못 찾는 일이 생기는데, 필요한 인수를 전부 명시해 두면 피할 수 있습니다.