excel VBA to update existing record in SQL - mysql

I currently have the below VBA to insert new records into my SQL Server from Excel.
Sub Button1_Click()
Dim conn As New ADODB.Connection
Dim iRowNo As Integer
Dim sCustomerId, sFirstName, sLastName As String
With Sheets("Sheet1")
'Open a connection to SQL Server
conn.Open "Provider=SQLOLEDB;Data Source=AUSWIDECUSTOMERS\SQL2012;Initial Catalog=Customers;Integrated Security=SSPI;"
'Skip the header row
iRowNo = 2
'Loop until empty cell in CustomerId
Do Until .Cells(iRowNo, 1) = ""
sCustomerId = .Cells(iRowNo, 1)
sFirstName = .Cells(iRowNo, 2)
sLastName = .Cells(iRowNo, 3)
'Generate and execute sql statement to import the excel rows to SQL Server table
conn.Execute "insert into dbo.Customers (CustomerId, FirstName, LastName) values ('" & sCustomerId & "', '" & sFirstName & "', '" & sLastName & "')"
iRowNo = iRowNo + 1
Loop
MsgBox "Customers imported."
conn.Close
Set conn = Nothing
End With
End Sub
What I am wanting to do is if anything changes with the sCustomerId record I inserted that I can come back in and update it.
So for example
current data set:
sCustomerId = 15 sFirstName = David SLastName = Smith
So from excel I want it to be able type in sCustomerID = 15 then update the record SLastName = Warner
Any ideas on how to make this change would be great.

Something like this should work.
In the example only prints the SQL in the Immediate Pane of the debugger. Since the OP is already familiar with reading from the database, updating it is left to the OP.
Updated to actually update the database.
The code presented below should be in the worksheet module for the worksheet containing the data.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rChangableData As Range
Dim rUpdatedData As Range
' Column headings A1, B1, C1
' CustomerId in Column A
' Range of data that can affect the change B2:C100
' This would be better implemented as a named range,
' but it is less transparent in the source code what it refers to
' * Simply entering a CustomerId, does not add a row
Set rChangableData = Me.Range("B2:C100")
' rUpdatedData is the range of changed data (Target),
' intersecting with the range of changable data (rChangeableData).
' If the two ranges do not intersect, rUpdatedData is Nothing and the event can be ignored
Set rUpdatedData = Intersect(rChangableData, Target)
If Not rUpdatedData Is Nothing Then
' Iterate over the range of changed data
' Obtain the CustomerId, FirstName and LastName values from the worksheet
' Provide to functions to perform the updates
' Also added a delete function where there is a CustomerId and no values for FirstName and LastName
Dim numRows As Long
Dim rowcounter As Long
Dim firstRow As Long
Dim lastRow As Long
Dim result As Integer
' Since the code needs to refer back to data on the worksheet,
' it keeps track of the row numbers in on the worksheet, rather than the changed data
numRows = rUpdatedData.Rows.Count
firstRow = Target.Row - rChangableData.Row + 1
rowcounter = firstRow
lastRow = firstRow + numRows
While rowcounter < lastRow
Dim CustomerId As Long
Dim FirstName As String
Dim LastName As String
Dim sql As String
CustomerId = rChangableData.Offset(0, -1).Cells(rowcounter, 1)
FirstName = rChangableData.Cells(rowcounter, 1)
LastName = rChangableData.Cells(rowcounter, 2)
If Trim(CustomerId) <> "" And Trim(FirstName) <> "" And Trim(LastName) <> "" Then
' The data has changed and there are non-blank values for CustomerId, FirstName and LastName;
' insert or update the customer
result = Customer_Update(CustomerId, FirstName, LastName)
If result = 0 Then
MsgBox "No rows were inserted or updated.", vbExclamation, "Customer Update"
Else
If result > 1 Then
MsgBox "Multiple rows were updated.", vbExclamation, "Customer Update"
End If
End If
Else
If Trim(CustomerId) <> "" And Trim(FirstName) = "" And Trim(LastName) = "" Then
' The data has changed and there is a non-blank value for CustomerID and
' blank values for FirstName and LastName;
' delete the customer
Customer_Delete CustomerId
If result = 0 Then
MsgBox "No rows were deleted", vbExclamation, "Customer Delete"
End If
End If
End If
rowcounter = rowcounter + 1
Wend
End If
End Sub
The code presented below should be in separate module in the same VBA project. This code handles connecting to and updating the customers.
Option Explicit
Private Function CreateSQLConnection() As ADODB.Connection
' Create an ADODB Connection.
' Settings depend on your own specific environment
Dim provider As String
Dim source As String
Dim database As String
Dim credentials As String
Dim connectionString As String
Dim sqlConn As ADODB.Connection
' Original Connection String
' "Provider=SQLOLEDB;Data Source=AUSWIDECUSTOMERS\SQL2012;Initial Catalog=Customers;Integrated Security=SSPI;"
provider = "SQLOLEDB"
source = "AUSWIDECUSTOMERS\SQL2012"
database = "Customers"
credentials = "Integrated Security=SSPI"
connectionString = "" & _
"Provider=" & provider & ";" & _
"Data Source=" & source & ";" & _
"Initial Catalogue=" & database & ";" & _
credentials & ";"
Set sqlConn = New ADODB.Connection
sqlConn.Open connectionString
sqlConn.DefaultDatabase = database
Set CreateSQLConnection = sqlConn
End Function
Public Function Customer_Update(CustomerId As Long, FirstName As String, LastName As String) As Integer
' Update or Insert a customer.
' * Creates a connection
' * Performs an update to the customer
' * Checks the number of rows affected
' * If no rows are affected, inserts the customer instead
Dim sqlConn As ADODB.Connection
Dim sqlCmd As ADODB.Command
Dim sqlParam As ADODB.Parameter
Dim rowsUpdated As Long
Set sqlConn = CreateSQLConnection()
Set sqlCmd = New ADODB.Command
sqlCmd.ActiveConnection = sqlConn
sqlCmd.CommandType = adCmdText
sqlCmd.CommandText = "update customer set FirstName = ?, LastName = ? where CustomerId = ?"
sqlCmd.Parameters.Append sqlCmd.CreateParameter("FirstName", adVarChar, adParamInput, Size:=255, Value:=FirstName)
sqlCmd.Parameters.Append sqlCmd.CreateParameter("LastName", adVarChar, adParamInput, Size:=255, Value:=LastName)
sqlCmd.Parameters.Append sqlCmd.CreateParameter("CustomerId", adInteger, adParamInput, Value:=CustomerId)
sqlCmd.Execute recordsAffected:=rowsUpdated
Set sqlCmd = Nothing
Customer_Update = Handle_UpdateInsertDeleteRows(rowsUpdated)
If Customer_Update = 0 Then
Dim rowsInserted As Long
Set sqlCmd = New ADODB.Command
sqlCmd.ActiveConnection = sqlConn
sqlCmd.CommandType = adCmdText
sqlCmd.CommandText = "insert into customer ( CustomerId, FirstName, LastName ) values ( ?, ?, ? )"
sqlCmd.Parameters.Append sqlCmd.CreateParameter("CustomerId", adInteger, adParamInput, Value:=CustomerId)
sqlCmd.Parameters.Append sqlCmd.CreateParameter("FirstName", adVarChar, adParamInput, Size:=255, Value:=FirstName)
sqlCmd.Parameters.Append sqlCmd.CreateParameter("LastName", adVarChar, adParamInput, Size:=255, Value:=LastName)
sqlCmd.Execute recordsAffected:=rowsInserted
Customer_Update = Handle_UpdateInsertDeleteRows(rowsInserted)
Set sqlCmd = Nothing
End If
sqlConn.Close
Set sqlConn = Nothing
End Function
Public Function Customer_Delete(CustomerId As Long) As Integer
' Delete a customer.
' * Creates a connection
' * Performs an delete on the customer table
Dim sqlConn As ADODB.Connection
Dim sqlCmd As ADODB.Command
Dim sqlParam As ADODB.Parameter
Dim rowsDeleted As Long
Set sqlConn = CreateSQLConnection()
Set sqlCmd = New ADODB.Command
sqlCmd.ActiveConnection = sqlConn
sqlCmd.CommandType = adCmdText
sqlCmd.CommandText = "delete customer where CustomerId = ?"
sqlCmd.Parameters.Append sqlCmd.CreateParameter("CustomerId", adInteger, adParamInput, Value:=CustomerId)
sqlCmd.Execute recordsAffected:=rowsDeleted
Set sqlCmd = Nothing
Customer_Delete = Handle_UpdateInsertDeleteRows(rowsDeleted)
sqlConn.Close
Set sqlConn = Nothing
End Function
Private Function Handle_UpdateInsertDeleteRows(recordsAffected As Long) As Integer
' Returns:
' * 0 for no rows
' * 1 for single row
' * 2 for multi row
Select Case recordsAffected
Case Is <= 0
Handle_UpdateInsertDeleteRows = 0
Case Is = 1
Handle_UpdateInsertDeleteRows = 1
Case Is > 1
Handle_UpdateInsertDeleteRows = 2
End Select
End Function

Related

How to insert a column's values into an SQL where statement using VBA

I have a list of account ID in column A. The range of that column is dynamic. How do I write a module that will take those values and use them in an SQL IN statement. Below is my attempt at doing this. I pieced together multiple scripts I found so sorry if it is a mess.
Sub ConnectSqlServer()
Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim sConnString As String
Dim wbBook As Workbook
Dim wsSheet As Worksheet
Dim lastrow As Long
Dim sl As Long
With wsSheet
lastrow = .Range("A" & .Rows.Count).End(xlUp).Row
End With
' Appending the values to a single variable
For i = 1 To lastrow
s1 = s1 & "'" & Val(wsSheet.Cells(i, 1)) & "'" & ","
Next
' Variable which could be used in IN command
If lastrow > 0 Then
s1 = Mid(s1, 1, Len(s1) - 1)
s1 = "(" & s1 & ")"
Else
Exit Sub
End If
' ' Create the connection string.
sConnString = "Driver={ODBC Driver 13 for SQL Server}; Server=snapshot;" & _
"Database=salesforce_replica;" & _
"Trusted_Connection=yes;"
' Create the Connection and Recordset objects.
Set conn = New ADODB.Connection
Set rs = New ADODB.Recordset
' Open the connection and execute.
conn.Open sConnString
Set rs = conn.Execute("SELECT * FROM dbo.account where Account_ID_18__c = " & s1;)
' Check we have data.
If Not rs.EOF Then
' Transfer result.
Sheets(1).Range("A1").CopyFromRecordset rs
' Close the recordset
rs.Close
Else
MsgBox "Error: No records returned.", vbCritical
End If
' Clean up
If CBool(conn.State And adStateOpen) Then conn.Close
Set conn = Nothing
Set rs = Nothing
End Sub
My goal is to figure out how to take a dynamic range of values and use them within an SQL Where statement.
Try something like this:
Sub ConnectSqlServer()
Dim conn As ADODB.Connection, rs As ADODB.Recordset
Dim sConnString As String
Dim wb As Workbook, ws As Worksheet, rngIds As Range, sql As String, inList As String
Set wb = ThisWorkbook
Set ws = wb.Sheets("list")
Set rngIds = ws.Range("A1:A" & ws.Cells(Rows.Count, "A").End(xlUp).Row)
inList = InClause(rngIds)
If Len(inList) = 0 Then
MsgBox "No id values!"
Exit Sub 'nothing to query...
End If
sConnString = "Driver={ODBC Driver 13 for SQL Server}; Server=snapshot;" & _
"Database=salesforce_replica;" & _
"Trusted_Connection=yes;"
Set conn = New ADODB.Connection
conn.Open sConnString
Set rs = conn.Execute("SELECT * FROM dbo.account where Account_ID_18__c in " & inList)
If Not rs.EOF Then
wb.Sheets(1).Range("A1").CopyFromRecordset rs
Else
MsgBox "Error: No records returned.", vbCritical
End If
rs.Close
conn.Close
End Sub
'Generate a SQL "in" list from distinct values in range `rng`
' Add single quotes around values unless `IsNumeric` is True
' Note if `rng` has too many values you may exceed your max. SQL query size!
Function InClause(rng As Range, Optional IsNumeric As Boolean = False) As String
Dim c As Range, dict As Object, arr, qt As String, v
Set dict = CreateObject("scripting.dictionary")
For Each c In rng.Cells
v = Trim(c.Value)
If Len(v) > 0 Then dict(v) = 1
Next c
If Not IsNumeric Then qt = "'"
If dict.Count > 0 Then
InClause = "(" & qt & Join(dict.keys, qt & "," & qt) & qt & ")"
End If
End Function

Save mySQL table to array and assign to worksheet - Excel VBA

I have adapted some code I found to extract a mySQL table and write it to a worksheet. However, it is slow for some of the larger tables(30,000+). I am trying to find a better way to import the values and avoid looping. I was hoping to be able to assign it directly to a range, but have been unsuccessful. From my research, it seems Excel is limited when it comes to mySQL. Any suggestions?
Dim password As String
Dim sqlstr As String
Dim dbTable As String
'OMIT Dim Cn statement
Dim server_Name As String
Dim user_ID As String
Dim database_Name As String
Dim lRow As Integer, lCol As Integer
'Start timer
Dim Count As Long
Dim BenchMark As Double
BenchMark = Timer
Application.ScreenUpdating = False
Application.EnableEvents = False
'OMIT Dim rs statement
Set rs = CreateObject("ADODB.Recordset") 'EBGen-Daily
server_Name = Sheet10.Range("b1").Value
database_Name = Sheet10.Range("b2").Value ' Name of database
user_ID = Sheet10.Range("b3").Value 'id user or username
password = Sheet10.Range("b4").Value 'Password
dbTable = Sheet10.Range("tbl_name").Value
sqlstr = "SELECT * FROM " & dbTable
Set cn = New ADODB.Connection
'On Error Goto ErrorHandler
cn.Open "DRIVER={MySQL ODBC 8.0 Unicode Driver};" & _
"SERVER=" & server_Name & ";" & _
"DATABASE=" & database_Name & ";" & _
"USER=" & user_ID & ";" & _
"PASSWORD=" & password & ";" & _
"Option=16427"
rs.Open sqlstr, cn, adOpenStatic
'MsgBox cn.Execute("SELECT COUNT(*) As row_count FROM elite_advocacy;")!row_count + 1
Dim myArray()
myArray = rs.GetRows()
kolumner = UBound(myArray, 1)
rader = UBound(myArray, 2)
'Delete existing table
On Error Resume Next
Sheet2.ListObjects("tbl_data").Delete
On Error GoTo 0
'Write array to sheet <<< Slow for large datasets
For k = 0 To kolumner ' Using For loop data are displayed
Sheet2.Range("rng_s_data").Offset(0, k).Value = rs.Fields(k).Name
For r = 0 To rader
Sheet2.Range("rng_s_data").Offset(r + 1, k).Value = myArray(k, r)
Next
Next
'Write array to range <<< Failed
'Attempt 2
'Dim r1 As Range, rBase As Range
'Dim L As Long, U As Long
'Set rBase = Sheet2.Range("rng_s_data")
'L = LBound(myArray)
'U = UBound(myArray)
'r1 = rBase.Resize(1, rader - kolumner + 1)
'r1 = myArray
'Find lRow and lCol
lRow = Cells(Rows.Count, Range("rng_s_data").Column).End(xlUp).Row
lCol = Cells(Range("rng_s_data").Row, Columns.Count).End(xlToLeft).Column
'Create a table from Data
'Sheet2.ListObjects.Add(xlSrcRange, Sheet2.Range("A$5:$Z$100"), , xlYes).Name = "tbl_data"
Sheet2.ListObjects.Add(xlSrcRange, Sheet2.Range(Sheet2.Cells(Sheet2.Range("rng_s_data").Row, Sheet2.Range("rng_s_data").Column), _
Sheet2.Cells(lRow, lCol)), , xlYes).Name = "tbl_data"
Sheet2.ListObjects("tbl_data").TableStyle = "TableStyleLight1"
'Autofit Sheet
Cells.EntireColumn.AutoFit
Application.ScreenUpdating = True
Application.EnableEvents = True
'End Timer
MsgBox Timer - BenchMark
Errorhandler:
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
End Sub
I don't have mySQl for testing, but something like this would be a generic approach to querying any database from Excel using ADO.
Performance is optimum if you avoid any looping which involves cell-by-cell access, and do as much as you can with arrays, before transferring the final array to the worksheet in a single operation.
It's worth putting in extra effort to create re-usable pieces of code as standalone Subs or Functions - that allows your main logic to stay focused on the task at hand.
Sub Tester()
Dim cn As ADODB.Connection, rs As ADODB.Recordset
Dim sql As String, dbTable As String, data, rngTbl As Range
Dim BenchMark As Double
BenchMark = Timer
Set cn = GetConnection()
Set rs = New ADODB.Recordset
dbTable = Sheet10.Range("tbl_name").Value
sql = "SELECT * FROM " & dbTable
rs.Open sql, cn, adOpenStatic
data = RecordSetToArray(rs) 'Includes field names
'data = RecordSetToArray(rs,False) 'False = no field names
'Delete existing table
On Error Resume Next
sheet2.ListObjects("tbl_data").Delete
On Error GoTo 0
'put the data on the worksheet
Set rngTbl = ArrayToSheetRange(data, sheet2.Range("rng_s_data"))
With sheet2.ListObjects.Add(xlSrcRange, rngTbl, , xlYes)
.Name = "tbl_data"
.TableStyle = "TableStyleLight1"
.Range.EntireColumn.AutoFit
End With
Debug.Print "Done in " & Timer - BenchMark
End Sub
'return an opened connection object
Function GetConnection() As ADODB.Connection
Dim serverNm As String, userId As String, dbNm As String, pw As String
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
serverNm = Sheet10.Range("b1").Value
dbNm = Sheet10.Range("b2").Value ' Name of database
userId = Sheet10.Range("b3").Value 'id user or username
pw = Sheet10.Range("b4").Value 'Password
cn.Open "DRIVER={MySQL ODBC 8.0 Unicode Driver};" & _
"SERVER=" & serverNm & ";" & _
"DATABASE=" & dbNm & ";" & _
"USER=" & userId & ";" & _
"PASSWORD=" & pw & ";" & _
"Option=16427"
Set GetConnection = cn
End Function
'Create a 2-D array from a recordset
Function RecordSetToArray(rs As ADODB.Recordset, _
Optional IncludeFieldNames As Boolean = True)
Dim tmp, nC As Long, nR As Long, data, r As Long, c As Long, rowNum As Long
tmp = rs.GetRows() 'cols x rows
nC = UBound(tmp, 1) + 1 'zero-based --> 1-based
nR = UBound(tmp, 2) + 1
ReDim data(1 To nR + IIf(IncludeFieldNames, 1, 0), 1 To nC) 'allow for headers?
If IncludeFieldNames Then
For c = 1 To nC
data(1, c) = rs.Fields(c - 1).Name
Next c
rowNum = 1
End If
For r = 1 To nR
rowNum = rowNum + 1
For c = 1 To nC
data(rowNum, c) = tmp(c - 1, r - 1)
Next c
Next r
RecordSetToArray = data
End Function
'Fill an array to a worksheet starting at `rng`, and return the filled range
Function ArrayToSheetRange(data, rng As Range) As Range
Dim rv As Range
Set rv = rng.Cells(1).Resize(UBound(data, 1), UBound(data, 2))
rv.Value = data
Set ArrayToSheetRange = rv
End Function

Access Select IN using VBA function

So I have this SQL Query
SELECT *
FROM [Employee To Manager]
WHERE [Employee To Manager].[Manager UID] In(getMyTeamUserNames());
Which has a VBA function getMyTeamUserNames()
Public Function getMyTeamUserNames() As String
Dim rs As DAO.Recordset
Dim dbs As DAO.Database
Set dbs = CurrentDb
getMyTeamUserNames = commaDelimitArray(getTeamUserNames(getUserName, dbs))
End Function
Public Function commaDelimitArray(arrayStr) As String
Dim sepStr As String
sepStr = "','"
commaDelimitArray = "'" & Join(arrayStr, sepStr)
End Function
Public Function getTeamUserNames(username, dbs) As String()
Dim sqlstatement As String
sqlstatement = "SELECT * FROM [Employee to Manager] WHERE [Employee to
Manager].[Manager UID] = '" & username & "'"
Set rs = dbs.OpenRecordset(sqlstatement, dbOpenSnapshot)
Dim ComputerUsernames() As String
Dim FindRecordCount As Integer
If rs.EOF Then
FindRecordCount = 0
Exit Function
Else
rs.MoveLast
FindRecordCount = rs.RecordCount
End If
ReDim ComputerUsernames(FindRecordCount) As String
Dim i As Integer
i = 0
rs.MoveFirst
Do Until rs.EOF = True
ComputerUsernames(i) = rs("Computer Username")
If (ComputerUsernames(i) <> "") Then
i = i + 1
End If
If (ComputerUsernames(i - 1) <> username) Then
Dim recurResult() As String
recurResult = getTeamUserNames(ComputerUsernames(i - 1), dbs)
Dim resultSize As Integer
If Len(Join(recurResult)) > 0 Then
resultSize = UBound(recurResult) - LBound(recurResult) + 1
ReDim Preserve ComputerUsernames(UBound(ComputerUsernames) + resultSize)
For Each resultStr In recurResult
ComputerUsernames(i) = resultStr
If (ComputerUsernames(i) <> "") Then
i = i + 1
End If
Next resultStr
End If
End If
rs.MoveNext
Loop
ReDim Preserve ComputerUsernames(i - 1)
getTeamUserNames = ComputerUsernames
End Function
Query runs and I get no data.
However if I take the result from getMyTeamUserNames() and put it in the query by hand it works. getMyTeamUserNames() result varies from possibly 2 results to 40 (recursively gets subordinates all the way down the tree).
So a C Perkins specifically pointed out this would never work so I have rebuilt the query with some other queries.

Split unpredictable length comma separated field not taking first record in series

I am running some code to split a slash-separated field into multiple rows, but the first value in the series is not carrying over. Does anyone know what I'm missing. Also, Rows that only have one record are not carrying over.
Public Sub ReformatTable()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim rsADD As DAO.Recordset
Dim strSQL As String
Dim strMPG, strBusinessName, strCustomerNumber, strCustomerName, strCountStartDate, strCCStatus As String
Dim strSplitMPG As String
Dim varData As Variant
Dim i As Integer
Set db = CurrentDb
' Select all eligible fields (have a comma) and unprocessed (SPLIT_MPG is Null)
strSQL = "SELECT BUSINESS_NAME, CUSTOMER_NUMBER, CUSTOMER_NAME, COUNT_START_DATE, CC_STATUS, MPG, SPLIT_MPG FROM [tmStarCycleCountStatuses_SlashesforCommas] WHERE ([MPG] Like ""*/*"") AND ([SPLIT_MPG] Is Null)"
Set rsADD = db.OpenRecordset("tmStarCycleCountStatuses_SlashesforCommas", dbOpenDynaset, dbAppendOnly)
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
With rs
While Not .EOF
strMPG = !MPG
strBusinessName = !BUSINESS_NAME
strCustomerNumber = !CUSTOMER_NUMBER
strCustomerName = !CUSTOMER_NAME
strCountStartDate = !COUNT_START_DATE
strCCStatus = !CC_STATUS
varData = Split(strMPG, "/") ' Get all comma delimited fields
' Update First Record
.Edit
!SPLIT_MPG = Trim(varData(0)) ' remove spaces before writing new fields
.Update
' Add records with same first field
' and new fields for remaining data at end of string
For i = 1 To UBound(varData)
With rsADD
.AddNew
!MPG = strMPG
!SPLIT_MPG = Trim(varData(i)) ' remove spaces before writing new fields
!BUSINESS_NAME = strBusinessName
!CUSTOMER_NUMBER = strCustomerNumber
!CUSTOMER_NAME = strCustomerName
!COUNT_START_DATE = strCountStartDate
!CC_STATUS = strCCStatus
.Update
End With
Next
.MoveNext
Wend
.Close
rsADD.Close
End With
Set rsADD = Nothing
Set rs = Nothing
db.Close
Set db = Nothing
End Sub
I can't post images yet due to reputation constrictions, but here are some links.
Here's the multiple after the code:
https://s9.postimg.org/fn3u70b5b/Multiple.jpg
Here's the single records after code run:
https://s10.postimg.org/bfq9z4snt/Singles.jpg
I feel like there's something super simple that I'm missing here, but it looks like I'm already taking the MPG over, so i'm curious as to why I'm not getting the singles or the first of the series. Any help would be appreciated! Thank you.
It looks right to me, except that you have to declare like this:
Dim strMPG As String
Dim strBusinessNames As String
Dim strCustomerNumbers As String
Dim strCustomerNames As String
Dim strCountStartDates As String
Dim strCCStatus As String
I guess you will have to insert some lines with Debug.Print .. to narrow down the happenings.
Got it. Ended up changing my approach. This code will work. The pattern, regardless of length, would always be the same, so I used a Right/Left combo and integers
Public Sub ReformatmStarCycleCountStatusesTable()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL As String
Dim strMPG As String
Dim strBusinessName As String
Dim strCustomerNumber As String
Dim strCustomerName As String
Dim dteCountStartDate As Date
Dim strCCStatus As String
Dim strSplitMPG As String
Dim intRemainingLength As Integer
Dim intInitialLength As Integer
Dim intStartPoint As Integer
Dim varData As Variant
Set db = CurrentDb
DoCmd.SetWarnings False
' Select all eligible fields (have a comma)
strSQL = "SELECT * FROM [mStar Cycle Count Statuses] WHERE [PRODUCT_FILTER_VALUE] is not null"
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
With rs
While Not .EOF
strMPG = !PRODUCT_FILTER_VALUE
strBusinessName = !BUSINESS_NAME
strCustomerNumber = !CUSTOMER_NUMBER
dteCountStartDate = !COUNT_START_DATE
strCCStatus = !Status
intInitialLength = Len(strMPG)
intRemainingLength = intInitialLength
intStartPoint = 2
Do While intRemainingLength > 0
strSQL = "INSERT INTO tmStarCycleCountStatuses VALUES ('" & strBusinessName & "', '" & strCustomerNumber _
& "', #" & dteCountStartDate & "#, '" & strCCStatus & "', '" & Right(Left(strMPG, intStartPoint), 2) & "')"
DoCmd.RunSQL (strSQL)
intStartPoint = intStartPoint + 3
intRemainingLength = intRemainingLength - 3
Loop
intStartPoint = 1
.MoveNext
Wend
.Close
End With
DoCmd.SetWarnings True
Set rs = Nothing
db.Close
Set db = Nothing
End Sub

Excel VBA error 3704 operation not allowed when object is closed at ADODB.Recordset.AddNew

Please forgive the sloppy coding, but I was thrown onto a project to get data from a spreadsheet to SQL server and the deadline has been missed. I was able to initial get my first dataswipe using a SELECT statement, but I can't seem to switch it over to an UPDATE.
Here's the code. I get the runtime error 3704 operation not allowed when object is closed at the line rstRecordset.AddNew
Public cnnConn As ADODB.Connection
Public rstRecordset As ADODB.Recordset
Public cmdCommand As ADODB.Command
Public Const Server As String = "datguy"
Public SQLQuery As String
Option Explicit
Sub testupinsertupdate()
Dim wkb As Workbook
Dim wks As Worksheet
Dim sel As Range
Set wkb = ActiveWorkbook
Set wks = Sheets(1)
Set sel = Selection
With wks
'Declaration unit
Dim dataitem As String
Dim yr As Integer
Dim yrmax As Integer
Dim rxcount As Integer
Dim row As Integer
Dim col As String
Dim cleanup As String
Dim sqlrxcount As String
dataitem = .Range("B3").Value
yr = 6 'data only needs to go back to 2006
yrmax = .Range("C7").End(xlToRight).row + yr 'declarative count to the Right-Of-File
rxcount = 7
row = .Range("A" & .Rows.Count).End(xlUp).row 'declarative count to EOF
col = .Range("C6").End(xlToRight).Column
cleanup = "Data Unavailable"
sqlrxcount = .Range("A" & rxcount).Value
Set cnnConn = New ADODB.Connection
cnnConn.ConnectionString = "driver={SQL Server};server=" & Server & ";database=database;Trusted_Connection=Yes"
cnnConn.ConnectionTimeout = 800
cnnConn.Open
For rxcount = 7 To row
Set cmdCommand = New ADODB.Command
Set cmdCommand.ActiveConnection = cnnConn
With cmdCommand
.CommandTimeout = 0
.CommandText = "UPDATE table SET " & dataitem & " = '" & Cells(col).Value & "' WHERE RX_ID = '" & sqlrxcount & "'"
.CommandType = adCmdText
.Execute
Debug.Print cmdCommand.State
End With
Debug.Print cmdCommand.State
Set rstRecordset = New ADODB.Recordset
Set rstRecordset.ActiveConnection = cnnConn
rstRecordset.Open cmdCommand, , adOpenStatic, adLockBatchOptimistic
col = ("C" & rxcount)
For yr = 6 To yrmax
rstRecordset.AddNew '*** error pops!
rstRecordset.Fields("RX_ID") = Range("A" & rxcount).Value
rstRecordset.Fields("YEAR_REPORTED") = yr + 2000
If Range(col).Value = cleanup Then
rstRecordset.Fields(dataitem) = Null
Else: rstRecordset.Fields(dataitem) = Range(col).Value
End If
'debug line to show results
Debug.Print Range("A" & rxcount).Value, yr + 2000, Range(col).Value
col = Range(col).Offset(0, 1).Address
Next yr
Next rxcount
rstRecordset.UpdateBatch
rstRecordset.Close
cnnConn.Close
End With
End Sub
I don't feel like I'm doing the operations in order, but I'm just trying to get the initial load and then will worry about maintenance later. Why isn't the object(I assume this is the recordset) open when it was opened three lines before?
You are attempting to open a recordset based on an update not a select
rstRecordset.Open cmdCommand, , adOpenStatic, adLockBatchOptimistic
should be something like
rstRecordset.Open "select * from table",cnnconn, adOpenStatic, adLockBatchOptimistic