[엑셀 VBA] 예약 DB - 7. MySQL 클래스와 사용법
클래스를 만들고 사용하다 보니,
Connection String만 바꿔주면 MySQL, 엑세서, MS SQL, Oracle 등등
다 사용할 수 있기 때문에 범용으로 사용이 가능합니다.
하나의 함수 함수 하나씩 설명하고, 전체 소스는 맨 마지각에 두겠습니다.
- DB 정보와 커넥션 스트링 만들기
Private strConn As String Private conn As ADODB.Connection Private ServerAddress As String Private myDataBase As String Private myUserName As String Private myPassword As String Private port As String Private Sub Class_Initialize() End Sub Private Sub Class_Terminate() Call disconnect_mysql End Sub Private Function connecto_to_mysql() As Boolean ' ServerAddress = "localhost" ' myDataBase = "table1" ' myUserName = "root" ' myPassword = "0000" ' port = "3306" ' strConn = "Driver={MySQL ODBC 8.0 Unicode Driver};Server=" & ServerAddress & ";" & _ ' "Port= " & port & ";" & _ ' "Database=" & myDataBase & ";" & _ ' "Uid=" & myUserName & ";" & _ ' "Pwd=" & myPassword & ";" & _ ' "Connect Timeout=100;" mdGlobal.DBPath = ThisWorkbook.path & "\DB\tmp.accdb" If clsUtils Is Nothing Then Set clsUtils = New clsUtils If clsUtils.fileExists(DBPath) = False Then MsgBox "에러: 엑세스 파일을 찾을 수 없습니다.", vbCritical + vbOKOnly, "엑세스 파일" End If strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DBPath & ";Persist Security Info=False;" On Error GoTo Error_Section Set conn = New ADODB.Connection conn.Open strConn connecto_to_mysql = True Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: connecto_to_mysql", Err, False Call disconnect_mysql connecto_to_mysql = False End Function Public Function disconnect_mysql() As Boolean On Error GoTo Error_Section conn.Close Set conn = Nothing disconnect_mysql = True Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: disconnect_mysql", Err, False disconnect_mysql = False End Function
위에 주석 처리한 부분은 제 로칼 MySQL 서버의 주소이고,
DBPath 변수는 각종 Global 변수를 모아 놓은 Module에 있습니다.
mdGlobal.DBPath = ThisWorkbook.path & "\DB\tmp.accdb"
여기에 엑세스 파일이 있고, 최종 strConn 에 정보를 담고 Connection 인스턴스를
conn이라는 변수명으로 생성해 둡니다. 이 conn 객체를 통해서 엑세스이든, MySQL이든
DB 서버나 파일하고 통신을 할 수 있습니다.
2. SQL문으로 실행하기
' SQL문으로 실행 : INSERT, UPDATE, DELETE Public Function mysql_ExecSQL_strSQL(strSQL As String) As Boolean Dim aff As Long On Error GoTo Error_Section Call conn.Execute(strSQL, aff) mysql_ExecSQL_strSQL = IIf(aff > 0, True, False) Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_ExecSQL_strSQL", Err, False mysql_ExecSQL_strSQL = False End Function
SQL문을 인자로 넘겨수면 conn 개체를 통해 서버에 SQL문을 전송하고,
서버측에서 영향을 받은(affected) 레코드 갯수를 반환해서 돌려 줍니다.
위에서 aff 변수에 담긴 값이 0보다 크면 실행이 되었다는 의미이고,
0이면 어떤 이유에서던 실행이 안된 것입니다. 그 이유를 알아야 하기 때문에
Error_Section: 란에 에러 내용을 출려하는 부분을 만들어 놓았습니다.
3. 에러 메시시 출력
Public Sub err_MSG(funcName As String, Err As Variant, Optional message As String = "", Optional debugOnly As Boolean = True) Dim tmp As String tmp = "-------- " & funcName & " ----------" & vbNewLine tmp = tmp & Err.Number & ": " & Err.Description & vbNewLine tmp = tmp & "time: " & VBA.Now & vbNewLine tmp = tmp & "message: " & message & vbNewLine tmp = tmp & "---------------------- END ---------------------" Debug.Print tmp If debugOnly = False Then MsgBox tmp, vbCritical + vbOKOnly, "WARNING!!!!" End If End Sub
이 함수는 클래스가 아닌 다른 모듈에 있는 에러 출력용 함수 입니다.
개발 단계에서는 어떤 에러가 나는지 구체적으로 파악해야 대처할 수 있기 때문에,
함수 이름, 에러 넘버, 에러 내용 등등 출력을 하게 합니다.
4. conn 개체를 이용한 SELECT 데이터 가져오기
' SQL문으로 실행 : SELECT 시 rs.recordcount=-1로 반환되는 단점이 있다. affectedRow 속성을 같이 반환한 방법을 생각해야 할 듯 Public Function mysql_ExecSQL_Recordset(ByVal strSQL As String) As Variant Dim aff As Long Dim rs As New ADODB.Recordset On Error GoTo Error_Section Set rs = conn.Execute(strSQL, aff) If rs Is Nothing Then Set mysql_ExecSQL_Recordset = Nothing Else Set mysql_ExecSQL_Recordset = rs End If Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_ExecSQL_Recordset", Err, False mysql_ExecSQL_Recordset = False End Function니
SELECT 문은 update, delete, insert 문과는 달리 반환되어 오는 것이
선택된 레코드들이기 때문에 이를 담아둘 Recordset 객체가 필요합니다.
체크를 해서 Nothing이 아니면 recordset 객체를 반환해서 호출 함수가 넘겨 받아
시트에 일괄적으로 레코드들을 넘겨 줍니다.
저는 MySQL 인스턴스를 생성하기 위해 mdGlobal 이라는 모듈안에
아래의 함수를 만들어 편하게 사용하고 있습니다.
Public MySQL As clsMySQL Public Sub setMySQL(Optional opt As Boolean = True) If opt = True Then If MySQL Is Nothing Then Set MySQL = New clsMySQL Else If Not MySQL Is Nothing Then Set MySQL = Nothing End If End Sub
4.1. SELECT로 불러온 레코드를 시트에 뿌리기
Public Function refresh_table(tbName As String, Optional orderBy As Boolean = False) As Boolean Dim strSQL As String Dim dbTable As String dbTable = getDBTableName(tbName) If VBA.Len(dbTable) = 0 Then Exit Function If orderBy = False Then strSQL = "SELECT * FROM " & dbTable & ";" Else strSQL = "SELECT * FROM " & dbTable & " ORDER BY ODR;" End If Dim lobj As ListObject Set lobj = mdGlobal.getListObject("SCHEMA", tbName) refresh_table = mdDB.fetchData(lobj, strSQL) End Function테
테이블 이름과 시트상의 표를 가져와서 SQL문을 생성하고,
이를 아래의 함수에 넘겨 줍니다. 이렇게 하는 이유는
엑셀파일에 불러와야할 표가 5개가 있는데,
매번 ListObject 객체 생성해서 넘겨주고 하는 일이 번거롭고,
때로는 철자 실수도 하고 해서 자동으로 하게 해 놓았습니다.
'데이터를 DB에서 가져와서 해당 시트의 테이블에 뿌리기 Public Function fetchData(lobj As ListObject, strSQL As String) As Boolean Call mdGlobal.setMySQL(True) Dim rs As ADODB.Recordset On Error GoTo Error_Section Set rs = MySQL.mysql_SELECT(strSQL) 'Set rs = mySQL.mysql_ExecSQL_Recordset(strSQL) If Not rs Is Nothing Then Application.EnableEvents = False Application.ScreenUpdating = False If lobj.ListRows.Count > 0 Then lobj.DataBodyRange.delete lobj.ListRows.Add AlwaysInsert:=True lobj.DataBodyRange.Cells(1, 1).CopyFromRecordset rs End If Set lobj = Nothing rs.Close Set rs = Nothing Call mdGlobal.setMySQL(False) Application.EnableEvents = True Application.ScreenUpdating = True fetchData = True Exit Function Error_Section: mdMessage.err_MSG "mdDB: fetchData", Err, False Set lobj = Nothing Set rs = Nothing Call mdGlobal.setMySQL(False) Application.EnableEvents = True Application.ScreenUpdating = True fetchData = False End Function
Call mdGlobal.setMySQL(True) : MySQL Instance 생성
Set rs = mySQL.mysql_ExecSQL_Recordset(strSQL) : 해당 recordset을 반환 받음
위에 코드 보시면, 2개가 있는데, 아무거나 쓰셔도 됩니다.
If lobj.ListRows.Count > 0 Then lobj.DataBodyRange.delete : 표에 데이터가 있으면 삭제
lobj.ListRows.Add AlwaysInsert:=True : 표에 행을 추가모드로 변경
lobj.DataBodyRange.Cells(1, 1).CopyFromRecordset rs :
이 부분 알아 내는데 3개월 정도 걸렸습니다. 여기서 .Cells(1,1)을 안 주면,
날짜와 숫자의 값들이 모두 이상하게 변합니다. 날짜 자리에 숫자가 나오거나,
숫자 자리에 날짜가 나오고, 지 멋대로 나업니다. (엑셀의 최대 단점, 날짜/숫자 자동 변경)
이걸 일일히 보정해주는 함수도 만들었는다. .Cells(1,1)을 주고 나면 그런 현상이 사라집니다.
아래는 사용한 메모리 자원들 해제. Local 변수는 안해줘도 함수 종료 되면서 해제 되지만,
MySQL 글로벌 변수는 안해주면, 문제가 생길 수 있습니다.
이 엑세스 파일을 열어 놓고, 닫지 않으면, 여러명의 사용자가 동시에 접속했을 때,
CRUD를 사용할 수 없게 될 수도 있습니다. cursorType 같은 설정을 제대로 않하면.
Set lobj = Nothing
rs.Close Set rs = Nothing
Call mdGlobal.setMySQL(False)
4.2 Recordset을 이용한 SELECT 데이터 가져오기
Public Function mysql_SELECT(strSQL As String) As Variant Dim rs As New ADODB.Recordset ' rs.CursorLocation = adUseClient ' rs.ActiveConnection = Conn ' rs.Source = strSQL rs.Open strSQL, conn, CursorTypeEnum.adOpenDynamic, LockTypeEnum.adLockOptimistic 'adOpenDynamic = 2, adLockOptimistic= 3 ' rs.Open strSQL, conn ' Debug.Print rs.RecordCount On Error GoTo Error_Section If rs Is Nothing Then Set mysql_SELECT = Nothing Else Set mysql_SELECT = rs End If Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_SELECT", Err, False mysql_SELECT = False End Function
5. INSERT문에서 방금 삽입한 레코드 일련번호 가져오기
Insert의 경우 SQL문을 실행하면 되는데,
삽입한 일련 번호를 가져와야 하는 경우가 있습니다.
Public Function mysql_INSERT_strSQL(strSQL As String) As Long Dim aff As Byte, SER As Long On Error GoTo Error_Section Call conn.Execute(strSQL, aff) If aff > 0 Then SER = conn.Execute("SELECT @@Identity")(0) mysql_INSERT_strSQL = SER Else mysql_INSERT_strSQL = -1 End If Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_INSERT_strSQL", Err, False mysql_INSERT_strSQL = False End Function
conn.Execute("SELECT @@Identity")(0) : 이 코드를 실행하면 마지막에 삽입한 레코드의 일련번호를 반환해 줍니다.
5.1 데이터가 많아 SQL문을 만들기 부담 스런상황의 INSERT
제가 가장 즐겨 쓰는 방법입니다. SQL문을 만드는 것이 아니라,
필드명과 값을 배열로 반들어 인자로 넘겨 줍니다.
Public Function mysql_INSERT_Array(ByVal tbName As String, arrFields, arrValues) As Long On Error GoTo Error_Section 'rs.Open tbName, Conn, adOpenDynamic, adLockOptimistic, adCmdTable Dim rs As New ADODB.Recordset rs.ActiveConnection = conn rs.CursorType = adOpenDynamic rs.LockType = adLockOptimistic rs.Open tbName, , , , adCmdTable rs.AddNew arrFields, arrValues rs.update Dim SER: SER = conn.Execute("SELECT @@Identity")(0) mysql_INSERT_Array = IIf(SER > 0, SER, 0) Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_INSERT_Array", Err, False mysql_INSERT_Array = 0 End Function
rs.Open tbName, , , , adCmdTable : DB의 테이블 이름을 인자로 넘기로 Table로 작업하겠다는 옵션을 줍니다.
rs.AddNew arrFields, arrValues : 이러면 해당 테이블의 맨 마지막으로 커서를 이동하고 레코드를 넣습니다. 취소할 것을 대비해서 가상으로 넣은 것이고 마지막에 반드시 rs.update 를 해 주어야 비로서 들어갑니다.
5.2 시트의 Range 범위를 입력하여 하는 방법
예전에 즐겨 썼는데... 코드가 지저분해지고,
Range가 변하면 매번 수정을 해야 하는 단점이 있습니다.
그래서 찾아낸 것이 ListObject를 쓰는 것이고 지금은 사용 안합니다.
Public Function MySQL_INSERT_Range(tbName As String, ws As Worksheet, rowStart As Long, rowEnd As Long, colStart As Long, colEnd As Long) As Boolean Dim rs As ADODB.Recordset Set rs = New ADODB.Recordset On Error GoTo Error_MySQL_INSERT_Range Dim strSQL As String strSQL = "SELECT * FROM " & tbName & ";" rs.Open strSQL, strConn, CursorTypeEnum.adOpenDynamic, LockTypeEnum.adLockOptimistic 'adOpenDynamic = 2, adLockOptimistic= 3 Dim row As Long, col As Long Dim fdName As String, val As Variant For row = rowStart To rowEnd rs.AddNew For col = colStart To colEnd fdName = Cells(1, col).Text val = Cells(row, col).value Debug.Print row & ":" & col & vbTab & fdName & ":" & val rs.Fields(fdName) = val Next col Debug.Print row Next row rs.update On Error GoTo 0 rs.Close Set rs = Nothing MySQL_INSERT_Range = True Exit Function Error_MySQL_INSERT_Range: MsgBox Err.Description, vbInformation Set rs = Nothing MySQL_INSERT_Range = False End Function
6. recordset을 이용한 UPDATE
간단한 update의 경우 SQL문을 쓰면 되지만,
필드와 값이 많으면, 그것을 일일히 SQL문으로 만드는 것도 힘듭니다.
INSERT처럼 필드와 값을 배열로 넘겨 주면 되는데, 한가지 다른 점이 있습니다.
WHERE문에 상당한 부분을 인자로 넘겨 주어야 하는데,
Public Function mysql_UPDATE_Recordset(ByVal tbName As String, ByVal criterion As String, arrFields, arrValues) As Boolean On Error GoTo Error_Section Dim rs As New ADODB.Recordset rs.ActiveConnection = conn rs.CursorType = adOpenDynamic rs.LockType = adLockOptimistic 'adLockPessimistic :다른 사용자가 이 레코드를 변경, 수정하지 못하게 락을 거는 rs.Open tbName, , , , adCmdTable ' Dim criteria As String: criteria = "Ser = " & key Dim criteria As String: criteria = criterion 'rs.MoveLast 'rs.Find criteria, , adSearchBackward rs.Find criteria rs.update arrFields, arrValues rs.Close Set rs = Nothing mysql_UPDATE_Recordset = True Exit Function Error_Section: ' rs.Close Set rs = Nothing mdMessage.err_MSG "clsMySQL: mysql_UPDATE_Recordset", Err, False mysql_UPDATE_Recordset = False End Function
Dim criteria As String: criteria = "Ser = " & key : "WHERE Ser = key" 이런 문구와 같은 것입니다.
rs.Find criteria : 해당 레코드를 찾아 그 위치로 커서를 이동합니다. 못 찾으면 에러를 발생시킵니다.
rs.update arrFields, arrValues : 배열에 담긴 값을 update해 줍니다.
recordset update는 에러가 없으면 결과 값이 성공이고, 있으면 실패가 됩니다.
그래서 반드시 에러 체크 루틴을 만들어 주어야 합니다.
7. 데이터의 존재 여부 확인
Function IsDataExist(strSQL As String) As Boolean Dim aff As Long On Error GoTo Error_Section Call conn.Execute(strSQL, aff) IsDataExist = IIf(aff > 0, True, False) Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: IsDataExist", Err, False IsDataExist = False End Function
가끔 업데이트 하기전이나 필요에 따라 레코드 존재 유무를 간단히 확인하고자 할 때
이 이외에 몇 개의 함수가 더 있기는 한데... 별로 중요치는 않아서... ^^
여기의 코드를 이해하신 다면, 제가 1년 정도 학습한 데이터베이스 다루는 기술을 다 습특하셨다고 보셔도 무방합니다.
8. clsMySQL 전체 소스
Option Explicit '// mySQL Connector/ODBC Driver 설치 //' '// https://dev.mysql.com/downloads/file/?id=506041 : ODBC '// https://dev.mysql.com/downloads/file/?id=506231 : ADO '// strPath : DB가 있는 엑셀 파일이음 //' '// strSQL : SQL문 //' '// pasteRange : 검색한 레코드를 붙여 넣을 범위 //' Private strConn As String Private conn As ADODB.Connection Private ServerAddress As String Private myDataBase As String Private myUserName As String Private myPassword As String Private port As String Private Sub Class_Initialize() 'If connecto_to_mysql = False Then Exit Sub End Sub Private Sub Class_Terminate() Call disconnect_mysql End Sub Private Function connecto_to_mysql() As Boolean ' strConn = "Driver={MySQL ODBC 8.0 Unicode Driver};Server=" & ServerAddress & ";" & _ ' "Port= " & port & ";" & _ ' "Database=" & myDataBase & ";" & _ ' "Uid=" & myUserName & ";" & _ ' "Pwd=" & myPassword & ";" & _ ' "Connect Timeout=100;" mdGlobal.DBPath = ThisWorkbook.path & "\DB\tmp.accdb" If clsUtils Is Nothing Then Set clsUtils = New clsUtils If clsUtils.fileExists(DBPath) = False Then MsgBox "에러: 엑세스 파일을 찾을 수 없습니다.", vbCritical + vbOKOnly, "엑세스 파일" End If strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DBPath & ";Persist Security Info=False;" On Error GoTo Error_Section Set conn = New ADODB.Connection conn.Open strConn connecto_to_mysql = True Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: connecto_to_mysql", Err, False Call disconnect_mysql connecto_to_mysql = False End Function Public Function disconnect_mysql() As Boolean On Error GoTo Error_Section conn.Close Set conn = Nothing disconnect_mysql = True Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: disconnect_mysql", Err, False disconnect_mysql = False End Function Private Sub closeRcordset(rs As ADODB.Recordset) If Not rs Is Nothing Then rs.Close Set rs = Nothing End If End Sub ' -------------------------------------------------------------------------------------- ' Data Handling------------------------------------------------------------------------- ' SQL문으로 실행 : INSERT, UPDATE, DELETE Public Function mysql_ExecSQL_strSQL(strSQL As String) As Boolean Dim aff As Long On Error GoTo Error_Section Call conn.Execute(strSQL, aff) mysql_ExecSQL_strSQL = IIf(aff > 0, True, False) Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_ExecSQL_strSQL", Err, False mysql_ExecSQL_strSQL = False End Function ' SQL문으로 실행 : SELECT 시 rs.recordcount=-1로 반환되는 단점이 있다. affectedRow 속성을 같이 반환한 방법을 생각해야 할 듯 Public Function mysql_ExecSQL_Recordset(ByVal strSQL As String) As Variant Dim aff As Long Dim rs As New ADODB.Recordset On Error GoTo Error_Section Set rs = conn.Execute(strSQL, aff) If rs Is Nothing Then Set mysql_ExecSQL_Recordset = Nothing Else Set mysql_ExecSQL_Recordset = rs End If Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_ExecSQL_Recordset", Err, False mysql_ExecSQL_Recordset = False End Function ' SELECT ---------------------------------------------------------------------- ' SELECT ---------------------------------------------------------------------- Public Function mysql_SELECT(strSQL As String) As Variant Dim rs As New ADODB.Recordset ' rs.CursorLocation = adUseClient ' rs.ActiveConnection = Conn ' rs.Source = strSQL rs.Open strSQL, conn, CursorTypeEnum.adOpenDynamic, LockTypeEnum.adLockOptimistic 'adOpenDynamic = 2, adLockOptimistic= 3 ' rs.Open strSQL, conn ' Debug.Print rs.RecordCount On Error GoTo Error_Section If rs Is Nothing Then Set mysql_SELECT = Nothing Else Set mysql_SELECT = rs End If Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_SELECT", Err, False mysql_SELECT = False End Function Public Function mysql_INSERT_strSQL(strSQL As String) As Long Dim aff As Byte, SER As Long On Error GoTo Error_Section Call conn.Execute(strSQL, aff) If aff > 0 Then SER = conn.Execute("SELECT @@Identity")(0) mysql_INSERT_strSQL = SER Else mysql_INSERT_strSQL = -1 End If Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_INSERT_strSQL", Err, False mysql_INSERT_strSQL = False End Function Public Function mysql_INSERT_Array(ByVal tbName As String, arrFields, arrValues) As Long On Error GoTo Error_Section 'rs.Open tbName, Conn, adOpenDynamic, adLockOptimistic, adCmdTable Dim rs As New ADODB.Recordset rs.ActiveConnection = conn rs.CursorType = adOpenDynamic rs.LockType = adLockOptimistic rs.Open tbName, , , , adCmdTable rs.AddNew arrFields, arrValues rs.update Dim SER: SER = conn.Execute("SELECT @@Identity")(0) mysql_INSERT_Array = IIf(SER > 0, SER, 0) Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: mysql_INSERT_Array", Err, False mysql_INSERT_Array = 0 End Function Public Function MySQL_INSERT_Range(tbName As String, ws As Worksheet, rowStart As Long, rowEnd As Long, colStart As Long, colEnd As Long) As Boolean Dim rs As ADODB.Recordset Set rs = New ADODB.Recordset On Error GoTo Error_MySQL_INSERT_Range Dim strSQL As String strSQL = "SELECT * FROM " & tbName & ";" rs.Open strSQL, strConn, CursorTypeEnum.adOpenDynamic, LockTypeEnum.adLockOptimistic 'adOpenDynamic = 2, adLockOptimistic= 3 Dim row As Long, col As Long Dim fdName As String, val As Variant For row = rowStart To rowEnd rs.AddNew For col = colStart To colEnd fdName = Cells(1, col).Text val = Cells(row, col).value Debug.Print row & ":" & col & vbTab & fdName & ":" & val rs.Fields(fdName) = val Next col Debug.Print row Next row rs.update On Error GoTo 0 rs.Close Set rs = Nothing MySQL_INSERT_Range = True Exit Function Error_MySQL_INSERT_Range: MsgBox Err.Description, vbInformation Set rs = Nothing MySQL_INSERT_Range = False End Function ' UPDATE ---------------------------------------------------------------------- ' UPDATE ---------------------------------------------------------------------- Public Function mysql_UPDATE_Recordset(ByVal tbName As String, ByVal criterion As String, arrFields, arrValues) As Boolean On Error GoTo Error_Section Dim rs As New ADODB.Recordset rs.ActiveConnection = conn rs.CursorType = adOpenDynamic rs.LockType = adLockOptimistic 'adLockPessimistic :다른 사용자가 이 레코드를 변경, 수정하지 못하게 락을 거는 rs.Open tbName, , , , adCmdTable ' Dim criteria As String: criteria = "Ser = " & key Dim criteria As String: criteria = criterion 'rs.MoveLast 'rs.Find criteria, , adSearchBackward rs.Find criteria rs.update arrFields, arrValues rs.Close Set rs = Nothing mysql_UPDATE_Recordset = True Exit Function Error_Section: ' rs.Close Set rs = Nothing mdMessage.err_MSG "clsMySQL: mysql_UPDATE_Recordset", Err, False mysql_UPDATE_Recordset = False End Function ' ----------------------------------------------------- ' ----------------------------------------------------- Function IsDataExist(strSQL As String) As Boolean Dim aff As Long On Error GoTo Error_Section Call conn.Execute(strSQL, aff) IsDataExist = IIf(aff > 0, True, False) Exit Function Error_Section: mdMessage.err_MSG "clsMySQL: IsDataExist", Err, False IsDataExist = False End Function ' 표 없데이트 또는 삽입 ------------------------------- ' ----------------------------------------------------- Public Function mysql_ListObject_Update(lobj As ListObject, tbName As String, criterion As String) As Boolean Dim criteria As String ' Dim arrFields(): arrFields = Array("Ser", "GC", "NET_WE", "NET_WD", "MEM_WE", "MEM_WD", "VIP_WE", "VIP_WD", "OTH_WE", "OTH_WD", "NOTE", "DEADLINE", "LIST_ORDER") Dim arrFields() Dim arrValues() Dim cnt As Long: cnt = lobj.ListRows.Count Dim key As Variant Dim row As Long Dim newSerial As Long On Error GoTo Error_Section arrFields = RangeToArray(lobj.HeaderRowRange, True, False) Dim rs As New ADODB.Recordset rs.ActiveConnection = conn rs.CursorType = adOpenDynamic rs.LockType = adLockOptimistic rs.Open tbName, , , , adCmdTable For row = 1 To cnt key = VBA.Trim(lobj.ListRows(row).Range(, 1).value) arrValues = RangeToArray(lobj.ListRows(row).Range, True, False) If VBA.Len(key) > 0 Then 'UPDATE criteria = criterion & key rs.MoveFirst rs.Find criteria rs.update arrFields, arrValues Debug.Print key & ": UPDATED" Debug.Print "-------------------------------------" Else 'INSERT rs.AddNew arrFields, arrValues rs.update newSerial = conn.Execute("SELECT @@Identity")(0) Debug.Print newSerial & ": INSERTED" Debug.Print "-------------------------------------" End If Next row rs.Close Set rs = Nothing mysql_ListObject_Update = True Exit Function Error_Section: Set rs = Nothing mdMessage.err_MSG "clsMySQL: mysql_ListObject_Update", Err, False mysql_ListObject_Update = False End Function Public Function RangeToArray(rng As Range, Optional tpose As Boolean = True, Optional includeIndex = False) Dim arr() Dim arrResult() Dim i As Long, index As Long, endIndex As Long arr = IIf(tpose, Application.Transpose(rng.value), rng.value) ' Debug.Print "rng LBound Value Columns: " & LBound(rng.Value, 1) : 헤더 포함 행의 개수 ' Debug.Print "rng UBound Value Columns: " & UBound(rng.Value, 2) : 칼럼의 개수 If includeIndex = False Then ReDim arrResult(1 To UBound(arr, 1) - 1) index = 2 endIndex = UBound(arr, 1) - 1 Else ReDim arrResult(1 To UBound(arr, 1)) index = 1 endIndex = UBound(arr, 1) End If Dim tmp For i = 1 To endIndex tmp = VBA.Trim(arr(index, 1)) If tmp = "" Then tmp = Null arrResult(i) = tmp continue: index = index + 1 Next i RangeToArray = arrResult End Function
번호 | 제목 | 작성자 | 작성일 | 추천 | 조회 |
[📚교재 출간 안내] 「진짜쓰는 실무엑셀」 , 드디어 출간되었습니다! (179)
![]() ![]() |
![]() ![]() |
2022.02.03 | 469 | 184806 | |
공지사항 |
[VBA] 구하라 그러면 주어질 것이다. - VBA 마스터 E-Book (영문판)
![]()
dra****
|
2022.07.19
|
추천 10
|
조회 772
|
![]() |
2022.07.19 | 10 | 772 |
45662 |
선택된 범위 정렬 단축키
(20)
![]() |
![]() |
2022.12.15 | 5 | 523 |
44293 |
[엑셀 VBA] 예약 DB - 9. 시트의 바우처&견적서 양식에 데이터 뿌리기
(15)
![]() |
![]() |
2022.11.11 | 4 | 888 |
![]()
blue_0313
|
2023.03.21
|
추천 0
|
조회 69
|
blue_0313 | 2023.03.21 | 0 | 69 | |
44227 |
[엑셀 VBA] 예약 DB - 8. Listbox 와 폼 컨트롤 연동하고 DB로 보내기
(1)
![]() |
![]() |
2022.11.09 | 3 | 566 |
44219 |
[엑셀 VBA] 예약 DB - 7. MySQL 클래스와 사용법
(3)
![]() |
![]() |
2022.11.09 | 2 | 514 |
43438 |
[엑셀 VBA] 예약 DB - 6. 폼 콘트롤과 DB 필드명 일치시키기
![]() |
![]() |
2022.10.21 | 2 | 310 |
43292 |
[엑셀 VBA] 예약 DB - 5. makeSQL() 함수 - INSERT, UPDATE문 자동 생성
(7)
![]() |
![]() |
2022.10.18 | 3 | 533 |
43091 |
[엑셀 VBA] 예약 DB - 4. 표 가지고 놀기
(17)
![]() |
![]() |
2022.10.13 | 1 | 695 |
43017 |
[엑셀 VBA] 예약 DB -3. 표(테이블, ListObject)을 사용해야 하는 이유1
(15)
![]() |
![]() |
2022.10.11 | 2 | 580 |
42998 |
[잡설] 엑셀이 웹으로 가야하는 이유2
(11)
![]() |
![]() |
2022.10.10 | 5 | 826 |
![]()
tin
|
2023.01.12
|
추천 0
|
조회 161
|
tin | 2023.01.12 | 0 | 161 | |
42982 |
[엑셀 VBA] 예약 DB - 2. 다시 웹으로 - Access에서 MySQL로 데이터 이식
![]() |
![]() |
2022.10.10 | 2 | 395 |
40590 |
[엑셀 VBA] 예약 DB - 1. 엑세스, SQL, Recordset, ListObject 의 상관 관계
(9)
![]() |
![]() |
2022.07.29 | 3 | 674 |
![]()
tin
|
2023.01.12
|
추천 0
|
조회 107
|
tin | 2023.01.12 | 0 | 107 | |
40511 |
[잡설] 엑셀의 꽃 파워 쿼리를 버리다.
(5)
![]() |
![]() |
2022.07.29 | 5 | 1152 |
40321 |
[경험담..해결했습니다.] &H80004005(-2147467259)시스템오류
(4)
![]() |
![]() |
2022.07.25 | 2 | 732 |
40074 |
M365 업데이트 이후 발생하는 H80004005 (-2147467259) 자동화 오류 해결방법
![]() ![]() |
![]() ![]() |
2022.07.23 | 1 | 511 |
39608 |
엑셀 그래프에 관한 유튜브 채널정보 입니다.
(16)
![]() |
![]() |
2022.07.15 | - | 395 |
36473 |
[엑셀VBA] 시트 이름을 변수로 설정하고 싶을때 간단한 방법
(3)
![]() |
![]() |
2022.06.27 | 2 | 1705 |
35196 |
Print_Area 동적 인쇄 영역설정
![]() ![]() |
![]() |
2022.06.21 | 4 | 1800 |
34607 |
셀레니움으로 개별공시지가 조회
![]() ![]() |
![]() |
2022.06.02 | 2 | 452 |
26273 |
엑셀 2021, M365 가로스크롤 기능
(39)
![]() ![]() |
![]() ![]() |
2022.01.23 | 17 | 1295 |
![]()
김학동
|
2022.01.23
|
추천 1
|
조회 353
|
김학동 | 2022.01.23 | 1 | 353 | |
![]()
김동희
|
2022.05.30
|
추천 0
|
조회 200
|
김동희 | 2022.05.30 | 0 | 200 | |
24189 |
[엑셀 VBA] Snippet - OCR: 이미지 파일을 텍스트 파일로 변환하기
(28)
![]() |
![]() |
2021.12.01 | 8 | 3516 |
![]()
tin
|
2023.01.12
|
추천 0
|
조회 90
|
tin | 2023.01.12 | 0 | 90 |
@dra**** 님 엑셀과 MySQL을 동시에 활용하는 그 순간 풀스택으로 개발자로 성장할 수 있습니다.
한가지 문제는 엑셀을 프론트로쓰면 보안이 걸린다는 것인데.. 적당히 trade-off 하면 웬만한 사업장에서는 거의 무결하게 사용할 수 있어서 증말 편리합니다 ㅎㅎ
@더블유에이 님 보안 부분은 엑셀 태생의 한계라 어쩔 수 없습니다.
다만 보안이 크게 문제가 안되는 소규모 사업체는 매우 유용합니다.
지금 개발해 드린 업체 사장님은 6명의 직원이 동시에 엑셀로 예약 업무를 하고 계시는데,
만족도가 높아서, 컨설팅 관련 부분도 개발해 달라 하시더군요.
자료 유출을 한다 해서 큰 문제가 되지도 않을 뿐더러, 매일 같이 DB를 백업 받아 놓으시기 때문에, 혹시 있을 지 모르는 불상사도 대비를 하고 계십니다.
엑셀 파일이야 개발한 제가 보관 중이니, 다시 보내드리면 되고.
Q&A에 올라오는 글들을 보면, 자동화를 갈구하시는 분들이 너무 많은데,
어떻게 해야할 지를 모르니 많이 안타까울 뿐입니다.
@dra**** 님 4.1 4번째 줄에
이건 데이터베이스에 테이블이 있는지 없는지 검사하기 위한 건가요?