해결 M365윈도우11
파워쿼리,VBA 질문입니다
프로그램 버전에따라 CSV파일 머릿글이 달라서 하나하고 똑같이 두번째 만드는데
무슨이유에서인지 이전엔 파일안에있던게 다 로드 됬었는데 안되네요..
샘플 파일기준으로 파일 취합하려면 어떻게 해야할까요
프로그램에서 뽑히는 데이터를 그대로 넣어두는거라 개별로 머릿글수정을 하긴 번거로울꺼같은데
버전 2개를 합쳐서 하나로 만들방법도 있을까요
추가로

Private Sub Worksheet_Change(ByVal Target As Range)
Application.ScreenUpdating = False
Application.EnableEvents = False
If Not Intersect(Target, Range("E4")) Is Nothing Then
'값이 변경된 셀이 "OO"셀 이면
OutLine
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
이렇게 했는데 자동실행이 안되는 이유와 해결방안도 궁금합니다
C4셀에 함수식이 적혀있어서 파워쿼리 새로고침하면 해당영역표가 만들어지고
VBA는 바뀌는 영역을 테두리 전체삭제한뒤 커런트리젼으로 다시 테두리 만드는거에요
무슨이유에서인지 이전엔 파일안에있던게 다 로드 됬었는데 안되네요..
샘플 파일기준으로 파일 취합하려면 어떻게 해야할까요
프로그램에서 뽑히는 데이터를 그대로 넣어두는거라 개별로 머릿글수정을 하긴 번거로울꺼같은데
버전 2개를 합쳐서 하나로 만들방법도 있을까요
추가로
Private Sub Worksheet_Change(ByVal Target As Range)
Application.ScreenUpdating = False
Application.EnableEvents = False
If Not Intersect(Target, Range("E4")) Is Nothing Then
'값이 변경된 셀이 "OO"셀 이면
OutLine
Application.ScreenUpdating = True
Application.EnableEvents = True
End Sub
이렇게 했는데 자동실행이 안되는 이유와 해결방안도 궁금합니다
C4셀에 함수식이 적혀있어서 파워쿼리 새로고침하면 해당영역표가 만들어지고
VBA는 바뀌는 영역을 테두리 전체삭제한뒤 커런트리젼으로 다시 테두리 만드는거에요
박
이
댓글 7
1. 첫번째 파일의 수식에 오류가 있어 다음과 같이 수정했으니 살펴보시구요~
=CHOOSECOLS(SORT(LET(r,UNIQUE(CSV_TBL[T/N]), f,LAMBDA(v,SORT(FILTER(CSV_TBL[[P/G]:[생크 길이]],v=CSV_TBL[T/N]),7)), DROP(REDUCE("",r,LAMBDA(a,b,VSTACK(a,f(b)))),1)),5,1),1,6,2,3,4,5,7,8,9)은 시트속성에 이미 있기 때문에 속성 에러가 계속 납니다. 이렇게 수정해 보세요~
시트에는,
Private Sub Worksheet_Calculate() Static LastValue As Variant Dim CurrentValue As Variant CurrentValue = Range("E4").Value If Not IsEqual(LastValue, CurrentValue) Then LastValue = CurrentValue Call ApplyGrid(Me) End If End Sub Private Function IsEqual(Val1 As Variant, Val2 As Variant) As Boolean If IsEmpty(Val1) And IsEmpty(Val2) Then IsEqual = True ElseIf IsEmpty(Val1) Or IsEmpty(Val2) Then IsEqual = False Else IsEqual = (Val1 = Val2) End If End Function모듈에는,
Public Sub ApplyGrid(ws As Worksheet) Dim rng As Range Application.ScreenUpdating = False Application.EnableEvents = False On Error GoTo ErrorHandler ws.UsedRange.Borders.LineStyle = xlNone Set rng = ws.Range("C3").CurrentRegion With rng.Borders .LineStyle = xlContinuous .Weight = xlThin .ColorIndex = xlAutomatic End With ErrorHandler: Application.ScreenUpdating = True Application.EnableEvents = True If Err.Number <> 0 Then MsgBox "오류가 발생했습니다: " & Err.Description, vbCritical End If End Sub Public Sub ApplyGridDelayed() Dim ws As Worksheet Set ws = ActiveSheet Call ApplyGrid(ws) End Sub추가로 제가 지금 VBA기초 챌린지 챕터3까지만 들은 VBA완전 쌩초보라 GPT도움받아 해석은 했는데 안배운 내용이 너무 많아서요
저는 아직 Sub로 매크로 이름 만들고 거기서 dim 다해두고 하는걸로 배웠는데
만들어주신건 public sub이고 applygrid에선 dim rng만 있고 그걸 applygriddelay가 데려가고 에러 핸들러도 시트가 아니라 모듈내용에 있고 그런 작성방식이 실무에서 필요한건가요?
특별한 이유가 있는건지 궁금합니다.
마지막으로 이렇게 저렇게 조작하다보니 E4셀값이 변하지 않는경우가 있더라구요
챗GPT가 RANGEVALUE기억해서 하는걸로 해보라고 했다가 난리가 났어요
어떻게해야할까요...
워크시트에서 배열수식 딜레이테스트로, E4 셀 값 변경 시 약간의 지연을 두고 실행되도록
If Not Intersect(Target, Range("E4")) Is Nothing Then Application.OnTime Now + TimeValue("00:00:01"), ... End If와 같은 코드가 들어가 있었는데, 이는 배열 수식 완료를 기다린 뒤 applygriddelay를 동작시키기 위해서 입니다. 워크시트에서 삭제했으니, 모듈에서도 삭제하시면 됩니다.
2. Sub와 Public Sub는 기능상 차이가 없습니다. 기본 접근 지정자는 Public이며,
단지 명시적으로 표시하느냐의 차이일 뿐입니다.
관례적으로는 외부 모듈에서 호출될 가능성이 있는 경우 Public Sub를 쓰고, 해당 모듈/시트 내부에서만 쓰이는 경우라면 Private Sub로 제한하는 것도 좋습니다.
2. 에러핸들러를 모듈에 두는 이유는
실행 중 오류가 발생할 경우, 그 오류를 모듈에서 처리하는 것이 가장 적절합니다.
그래서 시트 모듈은 E4 셀 값의 변경을 감지하는 역할만 하고,
실제 테두리 적용 및 예외 처리는 모듈에서 담당하도록 구조를 나눈 것입니다.
3. 말씀하신 “E4 셀 값이 변하지 않는 경우”가 구체적으로 어떤 상황인지 알려주시면,
해당 케이스를 직접 테스트해 보겠습니다. 가능하시다면 raw 데이터를 함께 올려주시면 더 정확하게 확인할 수 있습니다.
테스트해보실때 아랫쪽데이터가 아니라 윗쪽데이터를 지워보시면 알수있어요
E4셀이 공구경이라 같은 공구경이 제일작을경우엔 E4셀이 변하지 않고, 테두리범위는 변하고 하게되더라구여
이 파일에서,
CSV 파일에서 데이터를 복사해서 계속 붙여넣기 하면서 "공구확인용" 시트에 있는 테이블을 생성하는 작업 내용으로 이해하는 게 맞는가요?
2. 이때, E열 공구명의 E4값이 똑같은 새로운 값을 CSV 시트에 넣었을 경우, 테두리가 변해야 하는데 알맞게 변하지 않는다는 문제인가요?
즉, 기존에 5행 테두리였는데, 새로 붙인 데이터의 행이 3행일 경우,
E4값이 같으면, 데이터가 2행이 빈 상태로 있는데, 이 부분도 테두리가 둘러진 상태로 있는 문제가 발생한다는 말씀인가요?
특히 모듈에서 시트명을 상수로 설정해, 원하는 시트명으로 바꿀 수 있도록 했습니다~
Option Explicit ' ==================== 시트 정의 ==================== Public Const WS_MAIN As String = "공구확인용" Public Const WS_CSV As String = "CSV" Public Sub ApplyGrid(Optional ByRef L_DR As String = "") '// ---------------- 기본/상태 저장 ---------------- Dim ws As Worksheet: Set ws = Worksheets(WS_MAIN) Dim sht As Worksheet Dim prvCalc As XlCalculation On Error GoTo EH With Application .ScreenUpdating = False .EnableEvents = False prvCalc = .Calculation .Calculation = xlCalculationManual End With '// ---------------- 실제 그릴 범위 결정 ---------------- Dim d_RNG As Range Dim n_DR As String Dim hasSpill As Boolean: hasSpill = False On Error Resume Next hasSpill = ws.Range("C3").hasSpill On Error GoTo 0 If hasSpill Then '// 1) 스필이 있으면 스필범위로 Set d_RNG = ws.Range("C3").CurrentRegion Else '// 2) 스필이 없으면 예비: CSV의 eRow 기반 Set sht = ThisWorkbook.Worksheets(WS_CSV) Dim eRow As Long: eRow = sht.Cells(sht.Rows.Count, "B").End(xlUp).Row + 2 Dim cCol As Long: cCol = ws.Cells(3, ws.Columns.Count).End(xlToLeft).Column If eRow < 3 Then eRow = 3 Set d_RNG = ws.Range(ws.Cells(3, 3), ws.Cells(eRow, cCol)) End If n_DR = d_RNG.Address '// ---------------- 기존 테두리 지우기 ---------------- Call C_PB(ws, L_DR) '// ---------------- 데이터 없으면 종료 ---------------- If WorksheetFunction.CountA(d_RNG) = 0 Then L_DR = "" '// 빈 범위이므로 초기화 GoTo QH End If '// ---------------- 격자 그리기 ---------------- Call D_GB(d_RNG) '// 현재 그린 범위를 저장 L_DR = n_DR QH: With Application .ScreenUpdating = True .EnableEvents = True .Calculation = prvCalc End With Exit Sub EH: With Application .ScreenUpdating = True .EnableEvents = True .Calculation = prvCalc End With MsgBox "오류가 발생했습니다: " & Err.Description, vbCritical End Sub ' ==================== 이전 테두리 지우기 (최적화된 버전) ==================== Private Sub C_PB(ws As Worksheet, L_Rng As String) On Error Resume Next If L_Rng = "" Then Exit Sub ' 이전 범위가 없으면 종료 Dim eRng As Range Set eRng = ws.Range(L_Rng) '// 이전 테두리 완전 제거 With eRng.Borders .Item(xlEdgeLeft).LineStyle = xlNone .Item(xlEdgeTop).LineStyle = xlNone .Item(xlEdgeRight).LineStyle = xlNone .Item(xlEdgeBottom).LineStyle = xlNone .Item(xlInsideVertical).LineStyle = xlNone .Item(xlInsideHorizontal).LineStyle = xlNone End With On Error GoTo 0 End Sub ' ==================== 범위 포함 여부 확인 ==================== Private Function IS_rc(iRng As Range, oRng As Range) As Boolean On Error Resume Next IS_rc = False If iRng.Row >= oRng.Row And _ iRng.Column >= oRng.Column And _ (iRng.Row + iRng.Rows.Count - 1) <= (oRng.Row + oRng.Rows.Count - 1) And _ (iRng.Column + iRng.Columns.Count - 1) <= (oRng.Column + oRng.Columns.Count - 1) Then IS_rc = True End If On Error GoTo 0 End Function ' ==================== 격자 테두리 그리기 ==================== Private Sub D_GB(tRng As Range) On Error Resume Next With tRng.Borders ' 외곽 테두리 With .Item(xlEdgeLeft) .LineStyle = xlContinuous .Weight = xlThin .ColorIndex = xlAutomatic End With With .Item(xlEdgeTop) .LineStyle = xlContinuous .Weight = xlThin .ColorIndex = xlAutomatic End With With .Item(xlEdgeRight) .LineStyle = xlContinuous .Weight = xlThin .ColorIndex = xlAutomatic End With With .Item(xlEdgeBottom) .LineStyle = xlContinuous .Weight = xlThin .ColorIndex = xlAutomatic End With ' 내부 테두리 With .Item(xlInsideVertical) .LineStyle = xlContinuous .Weight = xlThin .ColorIndex = xlAutomatic End With With .Item(xlInsideHorizontal) .LineStyle = xlContinuous .Weight = xlThin .ColorIndex = xlAutomatic End With End With On Error GoTo 0 End Sub ' ==================== 전체 테두리 초기화 (필요시 사용) ==================== Public Sub cls_B() Dim ws As Worksheet: Set ws = Worksheets(WS_MAIN) With Application .ScreenUpdating = False .EnableEvents = False End With ' C3부터 사용된 영역 끝까지의 모든 테두리 제거 Dim eRow As Long: eRow = ws.Cells(ws.Rows.Count, "C").End(xlUp).Row Dim eCol As Long: eCol = ws.Cells(3, ws.Columns.Count).End(xlToLeft).Column If eRow < 3 Then eRow = 3 If eCol < 3 Then eCol = 12 ' L열 ws.Range(ws.Cells(3, 3), ws.Cells(eRow + 10, eCol)).Borders.LineStyle = xlNone With Application .ScreenUpdating = True .EnableEvents = True End With End Sub