엑셀 데이터 필터링 함수 :: Filtered_DB 명령문 사용법 총정리
엑셀 Filtered_DB 명령문 목차 바로가기
요약
엑셀 Filtered_DB는 데이터가 입력된 배열(DB)를 실시간으로 필터링하는 사용자 지정 함수입니다.
명령문 구문
Array = Filtered_DB ( DB, 조건, [열번호], [일치옵션] )
사용된 인수 및 변수 알아보기
인수 | 설명 |
DB [Variant] |
필터링 할 데이터가 입력된 배열(DB) 입니다. Get_DB 함수를 사용하면 시트 안에 입력된 데이터를 배열로 받아올 수 있습니다. |
조건 [Variant] |
필터링 할 조건입니다. 연산자(>,<,=)와 와일드카드(*,?)를 사용할 수 있습니다. |
열번호 [Long, 선택인수] |
배열에서 필터링 할 열 번호입니다. 열번호가 빈칸일 경우 배열의 모든 값을 대상으로 필터링합니다. 기본값은 빈칸입니다. |
일치옵션 [Boolean, 선택인수] |
정확히 일치 여부입니다. TRUE일 경우 조건과 정확히 일치하는 경우만 필터링합니다. 기본값은 FALSE 입니다. |
패치노트
- 2021.07.21
: 비어있는 DB를 입력할 경우, 오류 대신 비어있는 DB를 반환하도록 명령문 수정 - 2021.08.19
: 같지 않음 (<>) 조건으로도 필터링 할 수 있도록 명령문 개선
예제파일 다운로드
오빠두엑셀의 강의 예제파일은 여러분을 위해 자유롭게 제공하고 있습니다.
- [엑셀VBA함수] Filtered_DB 명령문예제파일
상세 설명
엑셀 Filtered_DB 함수는 데이터가 입력된 배열(DB)을 조건에 따라 필터링한 뒤, 필터링 된 결과를 배열로 반환하는 사용자 지정 함수입니다. Filtered_DB 함수는 다른 DB 관련 함수와 함께 여러 엑셀 프로그램을 제작할 때 매우 유용하게 사용할 수 있습니다.
Filtered_DB 함수는 데이터베이스 관련 VBA 함수 중 하나입니다. 더 다양한 DB 관련 함수는 아래 링크를 참고해주세요.
Filtered_DB 함수에 입력하는 조건은 1개만 입력가능하며 AND, OR 조건으로 동시에 필터링 할 수 없습니다. 만약 DB에 여러 조건을 적용하려면 Filtered_DB 함수를 여러번에 걸쳐 사용해야 하며, AND 조건으로만 필터링 할 수 있습니다.
함수의 마지막인수는 [정확히일치] 옵션이며 기본값은 유사일치입니다. 따라서 조건으로 "이"를 입력하면 DB에서 이를 포함하는 모든 값을 필터링합니다.
실전 사용 예제
- 직원정보 DB에서 나이가 20 이상인 직원 필터링
'직원정보 : 직원ID | 직원명 | 부서 | 직급 | 나이 Dim DB As Variant DB = Get_DB(ThisWorkbook.Worksheets("직원정보")) DB = Filtered_DB(DB, ">=20", 5) '직원정보DB에서 나이가 20 이상인 직원만 필터링됩니다.
- 직원정보 DB에서 성이 이씨이고 나이가 20 이상인 직원 필터링
'직원정보 : 직원ID | 직원명 | 부서 | 직급 | 나이 Dim DB As Variant DB = Get_DB(ThisWorkbook.Worksheets("직원정보")) DB = Filtered_DB(DB, "이*") DB = Filtered_DB(DB, ">=20", 5) '직원정보에서 성이 이씨이고 나이가 20 이상인 직원을 필터링합니다.
엑셀 데이터 필터링 함수, Filtered_DB 명령문 동작원리
Filtered_DB 명령문 전체 코드
'############################################################### '오빠두엑셀 VBA 사용자지정함수 (https://www.oppadu.com) '수정 및 배포 시 출처를 반드시 명시해야 합니다. '■ Filtered_DB 함수 '■ 서로 다른 두 시트를 연결합니다. FromWS의 첫번째 필드는 반드시 고유값(ID)이 입력되어야 합니다. '■ 사용방법 'Array = Filtered_DB(Get_DB(Sheet1),">=200") '■ 인수 설명 '_____________DB : 데이터를 필터링 할 원본 DB 입니다. '_____________Value : 필터링 할 조건입니다. '_____________FilterCol : [선택인수] 필터링 할 검색 열입니다. 빈칸일 경우 전체 열을 대상으로 필터링합니다. '_____________ExactMatch : [선택인수] 정확히 일치 여부입니다. 기본값은 False(=유사일치) 입니다. '############################################################### Function Filtered_DB(DB, Value, Optional FilterCol, Optional ExactMatch As Boolean = False) As Variant Dim cRow As Long Dim cCol As Long Dim vArr As Variant: Dim s As String: Dim filterArr As Variant: Dim Cols As Variant: Dim Col As Variant: Dim Colcnt As Long Dim isDateVal As Boolean Dim vReturn As Variant: Dim vResult As Variant Dim Dict As Object: Dim dictKey As Variant Dim i As Long: Dim j As Long Dim Operator As String '<-- 21.08.19 수정 : DB 비어있을 시, 오류 대신 비어있는 DB 반환 --> If IsEmpty(DB) Then Filtered_DB = DB: Exit Function Set Dict = CreateObject("Scripting.Dictionary") If Value <> "" Then cRow = UBound(DB, 1) cCol = UBound(DB, 2) ReDim vArr(1 To cRow) For i = 1 To cRow s = "" For j = 1 To cCol s = s & DB(i, j) & "|^" Next vArr(i) = s Next If IsMissing(FilterCol) Then filterArr = vArr Else Cols = Split(FilterCol, ",") ReDim filterArr(1 To cRow) For i = 1 To cRow s = "" For Each Col In Cols s = s & DB(i, Trim(Col)) & "|^" Next filterArr(i) = s Next End If If Left(Value, 2) = ">=" Or Left(Value, 2) = "<=" Or Left(Value, 2) = "=>" Or Left(Value, 2) = "=<" Or Left(Value, 2) = "<>" Then Operator = Left(Value, 2) If IsDate(Right(Value, Len(Value) - 2)) Then isDateVal = True ElseIf Left(Value, 1) = ">" Or Left(Value, 1) = "<" Then Operator = Left(Value, 1) If IsDate(Right(Value, Len(Value) - 1)) Then isDateVal = True Else: End If '<-- 21.08.19 수정 : 제외조건(<>)으로 필터링 가능하도록 수정 --> If Operator <> "" And Operator <> "<>" And Operator <> "=" Then If isDateVal = False Then Select Case Operator Case ">" For i = 1 To cRow If CDbl(Left(filterArr(i), Len(filterArr(i)) - 2)) > CDbl(Right(Value, Len(Value) - 1)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case "<" For i = 1 To cRow If CDbl(Left(filterArr(i), Len(filterArr(i)) - 2)) < CDbl(Right(Value, Len(Value) - 1)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case ">=", "=>" For i = 1 To cRow If CDbl(Left(filterArr(i), Len(filterArr(i)) - 2)) >= CDbl(Right(Value, Len(Value) - 2)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case "<=", "=<" For i = 1 To cRow If CDbl(Left(filterArr(i), Len(filterArr(i)) - 2)) <= CDbl(Right(Value, Len(Value) - 2)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next End Select Else Select Case Operator Case ">" For i = 1 To cRow If CDate(Left(filterArr(i), Len(filterArr(i)) - 2)) > CDate(Right(Value, Len(Value) - 1)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case "<" For i = 1 To cRow If CDate(Left(filterArr(i), Len(filterArr(i)) - 2)) < CDate(Right(Value, Len(Value) - 1)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case ">=", "=>" For i = 1 To cRow If CDate(Left(filterArr(i), Len(filterArr(i)) - 2)) >= CDate(Right(Value, Len(Value) - 2)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case "<=", "=<" For i = 1 To cRow If CDate(Left(filterArr(i), Len(filterArr(i)) - 2)) <= CDate(Right(Value, Len(Value) - 2)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next End Select End If Else If ExactMatch = False Then If Operator = "<>" Then Value = Right(Value, Len(Value) - 2) For i = 1 To cRow If Not filterArr(i) Like "*" & Value & "*" Then vArr(i) = Left(vArr(i), Len(vArr(i)) - 2) vReturn = Split(vArr(i), "|^") Dict.Add i, vReturn End If Next Else For i = 1 To cRow If filterArr(i) Like "*" & Value & "*" Then vArr(i) = Left(vArr(i), Len(vArr(i)) - 2) vReturn = Split(vArr(i), "|^") Dict.Add i, vReturn End If Next End If Else If Operator = "<>" Then Value = Right(Value, Len(Value) - 2) For i = 1 To cRow If Not filterArr(i) Like Value & "|^" Then vArr(i) = Left(vArr(i), Len(vArr(i)) - 2) vReturn = Split(vArr(i), "|^") Dict.Add i, vReturn End If Next Else For i = 1 To cRow If filterArr(i) = Value & "|^" Then vArr(i) = Left(vArr(i), Len(vArr(i)) - 2) vReturn = Split(vArr(i), "|^") Dict.Add i, vReturn End If Next End If End If End If If Dict.Count > 0 Then ReDim vResult(1 To Dict.Count, 1 To cCol) i = 1 For Each dictKey In Dict.Keys For j = 1 To cCol vResult(i, j) = Dict(dictKey)(j - 1) Next i = i + 1 Next End If Filtered_DB = vResult Else Filtered_DB = DB End If End Function Function Get_DB(WS As Worksheet, Optional NoID As Boolean = False, Optional IncludeHeader As Boolean = False) As Variant '############################################################### '오빠두엑셀 VBA 사용자지정함수 (https://www.oppadu.com) '수정 및 배포 시 출처를 반드시 명시해야 합니다. '■ Get_DB 함수 '■ 지정한 시트의 값을 배열로 반환합니다. 시트의 값은 반드시 A1셀에서 시작해야 합니다. 머릿글 우측으로 ID 값이 없을 경우 NoID를 TRUE로 사용합니다. '■ 사용방법 'Array = Get_DB(ThisWorkBook.WorkSheets("시트명"), TRUE) '▶ 인수 설명 '_____________WS : 배열로 변환할 시트 개체입니다. '_____________NoID : 머릿글 우측에 신규 ID값이 없을 경우, TRUE로 사용합니다. 기본값은 FALSE 입니다. '_____________IncludeHeader : True일 경우 배열에 머릿글을 포함합니다. 기본값은 FALSE 입니다. '############################################################### Dim cRow As Long Dim cCol As Long Dim offCol As Long If NoID = False Then offCol = -1 With WS cRow = .Cells(.Rows.Count, 1).End(xlUp).Row cCol = .Cells(1, .Columns.Count).End(xlToLeft).Column + offCol Get_DB = .Range(.Cells(2 + Sgn(IncludeHeader), 1), .Cells(cRow, cCol)) End With End Function
명령문 동작원리 단계별 알아보기
- 변수를 선언하고 Dictionary 개체를 설정합니다.
Dim cRow As Long Dim cCol As Long Dim vArr As Variant: Dim s As String: Dim filterArr As Variant: Dim Cols As Variant: Dim Col As Variant: Dim Colcnt As Long Dim isDateVal As Boolean Dim vReturn As Variant: Dim vResult As Variant Dim Dict As Object: Dim dictKey As Variant Dim i As Long: Dim j As Long Dim Operator As String Set Dict = CreateObject("Scripting.Dictionary")
- 결과값으로 반환 할 전체 배열(vArr)와 필터링 조건을 적용할 임시배열(filterArr)를 생성합니다.
If Value <> "" Then cRow = UBound(DB, 1) cCol = UBound(DB, 2) ReDim vArr(1 To cRow) For i = 1 To cRow s = "" For j = 1 To cCol s = s & DB(i, j) & "|^" Next vArr(i) = s Next If IsMissing(FilterCol) Then filterArr = vArr Else Cols = Split(FilterCol, ",") ReDim filterArr(1 To cRow) For i = 1 To cRow s = "" For Each Col In Cols s = s & DB(i, Trim(Col)) & "|^" Next filterArr(i) = s Next End If
- 조건으로 연산자(<,>,=)가 포함되어 있을 경우 명령문에 맞게 조건문을 변경합니다.
If Left(Value, 2) = ">=" Or Left(Value, 2) = "<=" Or Left(Value, 2) = "=>" Or Left(Value, 2) = "=<" Then Operator = Left(Value, 2) If IsDate(Right(Value, Len(Value) - 2)) Then isDateVal = True ElseIf Left(Value, 1) = ">" Or Left(Value, 1) = "<" Then Operator = Left(Value, 1) If IsDate(Right(Value, Len(Value) - 1)) Then isDateVal = True Else: End If
- 입력한 조건에 따라 DB를 필터링합니다.
If Operator <> "" Then If isDateVal = False Then Select Case Operator Case ">" For i = 1 To cRow If CDbl(Left(filterArr(i), Len(filterArr(i)) - 2)) > CDbl(Right(Value, Len(Value) - 1)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case "<" For i = 1 To cRow If CDbl(Left(filterArr(i), Len(filterArr(i)) - 2)) < CDbl(Right(Value, Len(Value) - 1)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case ">=", "=>" For i = 1 To cRow If CDbl(Left(filterArr(i), Len(filterArr(i)) - 2)) >= CDbl(Right(Value, Len(Value) - 2)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case "<=", "=<" For i = 1 To cRow If CDbl(Left(filterArr(i), Len(filterArr(i)) - 2)) <= CDbl(Right(Value, Len(Value) - 2)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next End Select Else Select Case Operator Case ">" For i = 1 To cRow If CDate(Left(filterArr(i), Len(filterArr(i)) - 2)) > CDate(Right(Value, Len(Value) - 1)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case "<" For i = 1 To cRow If CDate(Left(filterArr(i), Len(filterArr(i)) - 2)) < CDate(Right(Value, Len(Value) - 1)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case ">=", "=>" For i = 1 To cRow If CDate(Left(filterArr(i), Len(filterArr(i)) - 2)) >= CDate(Right(Value, Len(Value) - 2)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next Case "<=", "=<" For i = 1 To cRow If CDate(Left(filterArr(i), Len(filterArr(i)) - 2)) <= CDate(Right(Value, Len(Value) - 2)) Then: vArr(i) = Left(vArr(i), Len(vArr(i)) - 2): vReturn = Split(vArr(i), "|^"): Dict.Add i, vReturn Next End Select End If Else If ExactMatch = False Then For i = 1 To cRow If filterArr(i) Like "*" & Value & "*" Then vArr(i) = Left(vArr(i), Len(vArr(i)) - 2) vReturn = Split(vArr(i), "|^") Dict.Add i, vReturn End If Next Else For i = 1 To cRow If filterArr(i) Like Value & "|^" Then vArr(i) = Left(vArr(i), Len(vArr(i)) - 2) vReturn = Split(vArr(i), "|^") Dict.Add i, vReturn End If Next End If End If
- 출력할 배열(vResult)을 생성하고 배열 안에 값을 입력 후 함수 결과값으로 배열을 반환한 뒤 명령문을 종료합니다.
If Dict.Count > 0 Then ReDim vResult(1 To Dict.Count, 1 To cCol) i = 1 For Each dictKey In Dict.Keys For j = 1 To cCol vResult(i, j) = Dict(dictKey)(j - 1) Next i = i + 1 Next End If Filtered_DB = vResult Else Filtered_DB = DB End If
- 직원정보 DB에서 나이가 20 이상인 직원 필터링