이 페이지에서
구문
= Filtered_DB ( DB, 조건, [열번호], [일치옵션] )
인수구분
형식 설명
DB
필수
Variant
필터링 할 데이터가 입력된 배열(DB)입니다.
Get_DB 함수를 사용하면 시트 안에 입력된 데이터를 배열로 받아올 수 있습니다.
조건
필수
Variant
필터링 할 조건입니다.
연산자(>,<,=)와 와일드카드(*,?)를 사용할 수 있습니다.
열번호
선택
Long
배열에서 필터링 할 열 번호입니다. 기본값은 빈칸입니다.
열번호가 빈칸일 경우 배열의 모든 값을 대상으로 필터링합니다.
일치옵션
선택
Boolean
정확히 일치 여부입니다. 기본값은 FALSE 입니다.
TRUE 일 경우 조건과 정확히 일치하는 경우만 필터링합니다.
마스터 코드
복사한 코드는 VBA 편집기(Alt + F11) 새 모듈에 붙여넣어 사용하세요'###############################################################
'오빠두엑셀 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
활용 예제
나이가 20 이상인 직원만 필터링
'직원정보 : 직원ID | 직원명 | 부서 | 직급 | 나이
Dim DB As Variant
DB = Get_DB(ThisWorkbook.Worksheets("직원정보"))
DB = Filtered_DB(DB, ">=20", 5)
'직원정보DB에서 나이가 20 이상인 직원만 필터링됩니다.
조건을 두 번 적용해 성과 나이로 필터링
'직원정보 : 직원ID | 직원명 | 부서 | 직급 | 나이
Dim DB As Variant
DB = Get_DB(ThisWorkbook.Worksheets("직원정보"))
DB = Filtered_DB(DB, "이*")
DB = Filtered_DB(DB, ">=20", 5)
'직원정보에서 성이 이씨이고 나이가 20 이상인 직원을 필터링합니다.
안내사항
조건은 한 번에 하나만 입력할 수 있어 AND·OR 조건으로 동시에 필터링할 수 없습니다.
여러 조건을 적용하려면 Filtered_DB 를 여러 번 사용해 AND 조건으로만 필터링합니다.
시트 데이터를 배열로 받아오는 Get_DB 보조 함수가 함께 사용되며 위 전체 코드에 포함되어 있습니다.
ExactMatch를 True로 했을때는
Value = Right(Value, Len(Value) - 2) 구문이 없어 조건을 인식하지 못하는거 같은데 맞나요??
연산자가 있을 경우에는 대소비교를 하는 것이기 때문에, ExactMatch 여부 상관없이 사용할 수 있습니다.대소비교를 할 때에는, 정확히 일치/유사일치가 의미없기 때문입니다.^^
패치된 [ Filtered_DB 명령문 전체 코드] 를 적용하려고 하니까 사진처럼 빨간 부분이 생깁니다.
영상 보면서 공부 많이 하고 있습니다. 도움 주셔서 감사합니다.
홈페이지 글을 작성하는 과정에서 잠시 코드 줄바꿈에 문제가 있었습니다.
다시 수정해드렸으니 한번 확인해보시겠어요?
또는 예제파일에 적어드린 코드도 한번 확인해보세요.
감사합니다.
- 2021.08.19
- : 같지 않음 (<>) 조건으로도 필터링 할 수 있도록 명령문 개선
이 기능을 사용하고 싶은데 코드개선이 된게 맞을까요? 아무리 써봐도 안되서 코드도 한참 뜯어봤는데 어떻게 쓰는지 못찼겠어요 ㅠ예제파일에만 코드가 업데이트 되어 있습니다. 깜빡하고 홈페이지 코드는 수정을 못했네요.ㅡㅜ
방금 코드를 수정했으니 다시 확인해보시겠어요?:)
감사합니다.
filtered_db(X ,"<>" & 0 , X) 이런식으로 사용하였을때 0이 아닌값 즉 0보다 크거나 작은값이 필터링 될것이라고 생각했는데 0이 포함되지 않은값이 필터링이 됩니다.
예를들어 10이라는 값도 필터링이됩니다. 11은 필터링이 안되구요 전체 숫자중 0이 들어가면 필터링 되는것 같은데 이걸 의도하신걸까요..?
아직 코드를 제맘대로 수정할만한 실력이 안되서 질문드려봅니다 ㅠ
4번째 일치옵션 인수를 TRUE로 사용해보세요.
음 말씀하신대로 4번째 인수 true로 하니까 오히려 필터링이 하나도 안되고 0이나 10도 필터링이 안되네요 ㅠ 모든값이 다 나오는거 같아요. 제가 잘못 하고 있는걸까요?
명령문에 코드가 한 줄 빠져있었습니다.
수정된 코드를 다시 사용해보시겠어요?^^
감사합니다.
update_list 함수는 추후 기회가 될 때 머릿글을 포함할 수 있도록 수정해보겠습니다^^
좋은 의견 제공해주셔서 감사드립니다.
Filter_DB 매크로 기입 후 예제와 같이 DB 출력하고자 하는데, 사진의 노란색 디버그 오류로 인해 Filtered_DB가 제대로 작동하고 있지 않습니다.
해당 문장이 오류:13 - 형식이 일치하지 않습니다. 의 오류로 작동하지 않는데, 어떤 점이 문제인지 질문 드립니다.
우선 i와 j가 각각 몇인지 확인해보시고, s 값이 어떻게 설정되는지 한번 디버깅해보세요.
디버깅에 내용은 아래 게시글에서 자세히 안내하였으니 함께 확인해보시면 많은 도움이 되실겁니다.
https://www.oppadu.com/엑셀-vba-디버깅/
감사합니다.
셀서식은 통화로 돼있어서 $200.00이런식으로 셀에 표시가됩니다.
어떤행은 금액이 없고 어떤행은 금액값이 있습니다.
이 시트에서 금액이 들어가있는 행들만 필터해서 보고싶은데
DB = Filtered_DB(DB, ">="&0, 7) 이렇게 입력하니 구문오류라고 뜨고,
스페이스를 넣어서 DB = Filtered_DB(DB, ">="&0, 7) 이렇게 입력하면 '13' 런타임오류라고 뜹니다. ㅠㅠ
뭐가 문제인가요? [0보다크다] 말고 [값이 있다]를 조건으로 넣을수도 있나요?
디버깅오류는 적어주신 내용만으로는 확인이 어렵고, 아마 통화서식이여서 숫자가아닌 문자로 인식되어 오류가 발생하는 것으로 보입니다.
값이 있다 조건으로 보시려면,
이렇게 한번 사용해보시겠어요?
감사합니다.
Arr = Filtered_DB(Arr, "<=" & Sheet3.Range("k2"), 5, True)
이렇게 입력할 경우
13런타임 오류가 발생하면서 디버그시
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 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
https://www.oppadu.com/엑셀-vba-디버깅/
위 링크를 참고하셔서, value로 어떤 값이 들어갔을 때 오류가 발생하는지 한번 확인해보시겠어요?^^
감사합니다.
그러나 <> 연산자는 인식이 잘되어서요..
열번호를 안넣어서 그런가해서 열번호를 넣으면 s = s & DB(i, Trim(Col)) & "|^" 의 아래첨자가 잘못되었다는 오류가 발생합니다.
혹시나 해서 2010버전,2013버전 엑셀 전부 이용해봤고 저 디버깅 오류페이지도 계속 보고 있는데 뭣이 문제인지 잘 모르겠어서요..
재고관리완성파일에서 filterd_db함수만 끌어다 붙여도 봤는데 동일에러가 나와서 여쭈어봅니다.
첨부해주신 첨부파일을 조금 변경해보았는데요. 하나가 아닌
두 개의 조건으로 하려하는데
아래 부분이 잘못됬다고 뜨는데 어떻게 해야하나요?
s = s & DB(i, Trim(Col)) & "|^"
코드를 직접 수정하신 경우 중단점을 잡고 직접 디버깅해보시면 좋을 것 같습니다.
오류가 발생한 부분에 F9 키를 눌러 중단점 설정 후,
직접실행창과 지역창으로 각 변수가 잘 반환되는지 한번 확인해보세요.
https://www.oppadu.com/%ec%97%91%ec%85%80-vba-%eb%94%94%eb%b2%84%ea%b9%85/
디버깅 방법은 위 링크를 한번 참고해보시겠어요?
감사합니다.