Related
I'm getting an error message after the last loop runs in this procedure.The error is received after it cycles through the last worksheet in the excel workbook, and the line is "xl.ActiveSheet.Next.Select" (line 17 from the bottom). Can anyone give me a pointer? I've read and been told using .select is not ideal, but this is an older database I have inherited and would like to resolve this issue before improving the code.
The loop opens up an excel file and cycles through each worksheet (24 in this workbook) and imports the data to an access database. I've searched this topic but many issues seem unrelated, or much simpler to debug. I've even removed all but two worksheets and the error is still repeatable. Any help is appreciated! Thanks!
Private Sub lbl_WV_import_Click()
If gcfHandleErrors Then On Error GoTo Err_frmMe_home_lbl_WV_import
Dim xl As Object, wrkbk1 As Object
Dim pcd As String, pcd_title As String, model As String, station As String, task As String, pic As String, bom_pn As String, c1 As String, c2 As String, spec As String, sApp As String
Dim pn As String, pname As String, ts_part_name As String, ts_part_num As String, model_info As String, color As String, dest As String, tool As String, socket As String, torque As String, misc As String
Dim rev As Integer, zone As Integer, seq As Integer, mod_id As Integer, delta As Integer, st_seq As Integer, qty As Integer, i As Integer, J As Integer, ts_sec As Integer, sec As Integer, row As Integer
Dim pcd_id As LongPtr, stat_id As LongPtr, task_id As LongPtr, task_list_id As LongPtr, pn_id As LongPtr, tool_id As LongPtr, task_step_id As LongPtr
Dim pitch As Double
Set db = CurrentDb()
sApp = "Excel.Application"
If IsAppRunning(sApp) = True Then
Set xl = GetObject(, "Excel.Application")
For Each wrkbk1 In xl.Workbooks
If wrkbk1.Name = "P1_PCD.xlsm" Then
Exit For
End If
Next
strSQL = DLookup("db_loc", "tbl_ext_source") & DLookup("area", "tblArea") & "\P1_PCD.xlsm"
Set wrkbk1 = xl.Workbooks.Open(strSQL)
Else
Set xl = CreateObject("Excel.Application")
xl.Application.Visible = True
strSQL = DLookup("db_loc", "tbl_ext_source") & DLookup("area", "tblArea") & "\P1_PCD.xlsm"
Set wrkbk1 = xl.Workbooks.Open(strSQL)
End If
xl.Workbooks("P1_PCD.xlsm").Activate
xl.Sheets(1).Select
xl.Range("B1").Select
pcd_title = xl.Range("B1").Value
xl.Range("O2").Select
pitch = xl.Range("O2").Value
xl.Range("Q2").Select
pcd = "PCD-" & xl.Range("Q2").Value
xl.Range("R2").Select
rev = xl.Range("R2").Value
xl.Range("K3").Select
model = xl.Range("K3").Value
If IsNull(DLookup("model", "tblModel", "[model] = '" & model & "'")) Then
strSQL = "INSERT INTO tblModel (model) " _
& "Values ('" & model & "')"
db.Execute strSQL
lid = DMax("mod_id", "tblModel")
strSQL = "INSERT INTO " _
& "tblAudit (EditDate, RecordSource, RecordID, User, Field, BeforeValue, AfterValue) " _
& "VALUES (Now(), ""tblModel"", '" & lid & "', '" & fosUserName() & "', ""model"", ""New Record"", '" & model & "')"
db.Execute strSQL
End If
If IsNull(DLookup("pcd", "tblPCD", "pcd='" & pcd & "' AND rev=" & rev & "")) Then
mod_id = DLookup("mod_id", "tblModel", "[model] = '" & model & "'")
bom_pn = DLookup("ItemNo", "PYMAC", "LV = ""00""")
strSQL = "INSERT INTO tblPCD ( pcd, pcd_title, rev, mod_id, pitch, pre_rev, bom_pn ) " _
& "VALUES ('" & pcd & "','" & pcd_title & "', " & rev & ", " & mod_id & ", " & pitch & ", " & rev - 1 & ", '" & bom_pn & "')"
db.Execute strSQL
pcd_id = DLookup("pcd_id", "tblPCD", "pcd='" & pcd & "' AND rev=" & rev & "")
lid = DMax("pcd_id", "tblPCD")
strSQL = "INSERT INTO " _
& "tblAudit (EditDate, RecordSource, RecordID, User, Field, BeforeValue, AfterValue) " _
& "VALUES (Now(), ""tblPCD"", '" & lid & "', '" & fosUserName() & "', ""ALL"", ""New Record"", ""New PCD from excel "" & " & pcd_id & ")"
db.Execute strSQL
Call upload_pymac(pcd_id)
Set db = CurrentDb()
Else
If InputBox("This PCD already exists. Is this another section of this PCD that needs to be imported? [Y/N]") = "y" Then
Else
Exit Sub
End If
End If
pcd_id = DLookup("pcd_id", "tblPCD", "pcd='" & pcd & "' AND rev=" & rev & "")
If IsNull(DMax("seq", "tblTask", "[pcd_id] = " & pcd_id & "")) Then
seq = 1
Else
seq = DMax("seq", "tblTask", "[pcd_id] = " & pcd_id & "")
End If
For J = 1 To xl.ActiveWorkbook.Worksheets.Count
xl.Range("O3").Select
station = xl.Range("O3").Value
If IsNull(DLookup("station", "tblStation", "[station] = '" & station & "'")) Then
If IsNull(DMax("stat_id", "tblStation")) Then
sec = 1
Else
sec = DMax("stat_id", "tblStation") + 1
End If
strSQL = "INSERT INTO tblStation ( station, zone_id,sec ) " _
& "VALUES ('" & station & "',1," & sec & ")"
db.Execute strSQL
lid = DMax("stat_id", "tblStation")
strSQL = "INSERT INTO " _
& "tblAudit (EditDate, RecordSource, RecordID, User, Field, BeforeValue, AfterValue) " _
& "VALUES (Now(), ""tblStation"", '" & lid & "', '" & fosUserName() & "', ""ALL"", ""New Records"", ""New record for PCD "" & " & pcd_id & ")"
db.Execute strSQL
End If
stat_id = DLookup("stat_id", "tblStation", "[station] = '" & station & "'")
st_seq = 1
c1 = "C6"
xl.Range(c1).Select
Do Until xl.CountA(xl.ActiveCell) = 0
xl.Range(c1).Select
task = xl.ActiveCell.Value
If Len(task) > 250 Then
task = Left(task, 255)
End If
If IsNull(DLookup("task_txt", "tblTask_txt", "[task_txt] = '" & task & "'")) Then
strSQL = "INSERT INTO tblTask_txt ( task_txt ) " _
& "VALUES ('" & task & "')"
db.Execute strSQL
lid = DMax("task_list_id", "tblTask_txt")
strSQL = "INSERT INTO " _
& "tblAudit (EditDate, RecordSource, RecordID, User, Field, BeforeValue, AfterValue) " _
& "VALUES (Now(), ""tblTask_txt"", '" & lid & "', '" & fosUserName() & "', ""task_txt"", ""New Record"", '" & task & "')"
db.Execute strSQL
End If
task_list_id = DLookup("task_list_id", "tblTask_txt", "[task_txt] = '" & task & "'")
xl.ActiveCell.Offset(0, 4).Select
If xl.ActiveCell.Value = "Q" Then
delta = 1
ElseIf xl.ActiveCell.Value = "C" Then
delta = 2
ElseIf xl.ActiveCell.Value = "CTQ" Then
delta = 3
ElseIf xl.ActiveCell.Value = "R" Then
delta = 4
Else
delta = 0
End If
xl.ActiveCell.Offset(0, 1).Select
spec = Replace(xl.ActiveCell.Value, "'", "''")
If Len(spec) > 250 Then
spec = Left(spec, 255)
End If
strSQL = "INSERT INTO tblTask ( pcd_id, seq, stat_id, task_list_id, st_seq, spec_inst ) " _
& "Values (" & pcd_id & ", " & seq & ", " & stat_id & ", " & task_list_id & "," & st_seq & ", '" & spec & "')"
db.Execute strSQL
task_id = DMax("task_id", "tblTask")
lid = DMax("task_id", "tblTask")
strSQL = "INSERT INTO " _
& "tblAudit (EditDate, RecordSource, RecordID, User, Field, BeforeValue, AfterValue) " _
& "VALUES (Now(), ""tblTask_txt"", '" & lid & "', '" & fosUserName() & "', ""ALL"", ""New Record"", ""New record for PCD "" & " & pcd_id & ")"
db.Execute strSQL
row = xl.ActiveCell.row()
c2 = "E" & row
xl.Range(c2).Select
strSQL = DLookup("db_loc", "tbl_ext_source") & DLookup("area", "tblArea") & "\PICS\" & task_id & ".jpg"
xl.Run "getpic", strSQL
For i = 1 To 10
c2 = "K" & row & ":" & "T" & row
If xl.CountA(xl.Range(c2)) = 0 Then
Exit For
End If
c2 = "K" & row
xl.Range(c2).Select
c2 = xl.ActiveCell.Address
ts_part_num = ""
ts_part_name = ""
pn = ""
pname = ""
pn_id = 0
tool = ""
tool_id = 0
pname = xl.ActiveCell.Value
If pname = "Part Name" Then
Exit For
End If
xl.ActiveCell.Offset(0, 1).Select
pn = xl.ActiveCell.Value
If IsNull(DLookup("part_num", "tblPart_master", "[part_num] = '" & pn & "'")) Then
ts_part_num = pn
ts_part_name = pname
Else
pn_id = DLookup("pn_id", "tblPart_master", "[part_num] = '" & pn & "'")
End If
xl.ActiveCell.Offset(0, 1).Select
qty = xl.ActiveCell.Value
xl.ActiveCell.Offset(0, 1).Select
model_info = xl.ActiveCell.Value
xl.ActiveCell.Offset(0, 1).Select
color = xl.ActiveCell.Value
xl.ActiveCell.Offset(0, 1).Select
dest = xl.ActiveCell.Value
xl.ActiveCell.Offset(0, 1).Select
tool = xl.ActiveCell.Value
If Len(tool) > 1 Then
If IsNull(DLookup("tool_id", "tblTools", "[tool] = '" & tool & "'")) Then
strSQL = "INSERT INTO tblTools (tool, tool_type_id ) " _
& "Values ('" & tool & "',1)"
db.Execute strSQL
lid = DMax("tool_id", "tblTools")
strSQL = "INSERT INTO " _
& "tblAudit (EditDate, RecordSource, RecordID, User, Field, BeforeValue, AfterValue) " _
& "VALUES (Now(), ""tblTools"", '" & lid & "', '" & fosUserName() & "', ""tool"", ""New Record"", '" & tool & "')"
db.Execute strSQL
End If
tool_id = DLookup("tool_id", "tblTools", "[tool] = '" & tool & "'")
End If
xl.ActiveCell.Offset(0, 1).Select
socket = xl.ActiveCell.Value
xl.ActiveCell.Offset(0, 1).Select
torque = xl.ActiveCell.Value
xl.ActiveCell.Offset(0, 1).Select
misc = xl.ActiveCell.Value
strSQL = "INSERT INTO tblTask_steps ( task_id ) " _
& " Values ( " & task_id & " )"
db.Execute strSQL
task_step_id = DMax("task_step_id", "tblTask_steps")
strSQL = "INSERT INTO " _
& "tblAudit (EditDate, RecordSource, RecordID, User, Field, BeforeValue, AfterValue) " _
& "VALUES (Now(), ""tblTask_steps"", '" & task_step_id & "', '" & fosUserName() & "', ""ALL"", ""New Record"", ""New record for PCD "" & " & pcd_id & ")"
db.Execute strSQL
strSQL = "SELECT tblTask_steps.* " _
& "FROM tblTask_steps " _
& "WHERE (((tblTask_steps.task_step_id)=" & task_step_id & "))"
Set rs = db.OpenRecordset(strSQL)
If Len(ts_part_name) > 0 Then
rs.Edit
rs!ts_part_name = ts_part_name
rs.Update
End If
If Len(ts_part_num) > 0 Then
rs.Edit
rs!ts_part_num = ts_part_num
rs.Update
End If
If pn_id > 0 Then
rs.Edit
rs!pn_id = pn_id
rs.Update
End If
If qty > 0 Then
rs.Edit
rs!qty = qty
rs.Update
End If
If Len(model_info) > 0 Then
rs.Edit
rs!model_info = model_info
rs.Update
End If
If Len(color) > 0 Then
rs.Edit
rs!color = color
rs.Update
End If
If Len(dest) > 0 Then
rs.Edit
rs!dest = dest
rs.Update
End If
If tool_id > 0 Then
rs.Edit
rs!tool_id = tool_id
rs.Update
End If
If Len(socket) > 0 Then
rs.Edit
rs!socket = socket
rs.Update
End If
If Len(torque) > 0 Then
rs.Edit
rs!torque = torque
rs.Update
End If
If delta > 0 Then
rs.Edit
rs!delta = delta
rs.Update
End If
If Len(misc) > 0 Then
rs.Edit
rs!misc = misc
rs.Update
End If
xl.Range(c2).Select
xl.ActiveCell.Offset(1, 0).Select
row = xl.ActiveCell.row()
Next i
ts_sec = 0
xl.Range(c1).Select
xl.ActiveCell.Offset(1, 0).Select
If xl.ActiveCell.Column() <> 3 Then
row = xl.ActiveCell.row()
c1 = "C" & row + 1
xl.Range(c1).Select
End If
If xl.ActiveCell.Value = "Task Description" Then
xl.ActiveCell.Offset(1, 0).Select
If xl.ActiveCell.Column() <> 3 Then
row = xl.ActiveCell.row()
c1 = "C" & row + 1
xl.Range(c1).Select
End If
End If
If IsEmpty(xl.ActiveCell) Then
strSQL = DLookup("db_loc", "tbl_ext_source") & DLookup("area", "tblArea") & "\PICS\" & task_id & "_2.jpg"
xl.Run "getpic", strSQL
xl.ActiveCell.Offset(1, 0).Select
If xl.ActiveCell.Column() <> 3 Then
row = xl.ActiveCell.row()
c1 = "C" & row + 1
xl.Range(c1).Select
End If
End If
If xl.ActiveCell.Value = "Task Description" Then
xl.ActiveCell.Offset(1, 0).Select
If xl.ActiveCell.Column() <> 3 Then
row = xl.ActiveCell.row()
c1 = "C" & row + 1
xl.Range(c1).Select
End If
End If
c1 = xl.ActiveCell.Address
st_seq = st_seq + 1
seq = seq + 1
Loop
xl.ActiveSheet.Next.Select
Next J
xl.Application.ScreenUpdating = True
strSQL = "UPDATE tblTask SET tblTask.image_id = [task_id] " _
& "WHERE (((tblTask.pcd_id)=" & pcd_id & "))"
db.Execute strSQL
Call recal_secs(1, pcd_id, 0)
Call sort_stat_all(pcd_id)
MsgBox "The PCD has been imported. Go to stations and assure the zones are correct."
Set rs = Nothing
Set db = Nothing
Exit_frmMe_home_lbl_WV_import:
Exit Sub
Err_frmMe_home_lbl_WV_import:
Call LogError(Err.Number, Err.Description, "frmMe_home_lbl_WV_import()")
Resume Exit_frmMe_home_lbl_WV_import
End Sub
As I tried suggesting in my above comment, it looks that the way you designed the code (probably, mostly based on macro recorder...), using an unjustified number of selecting, makes the code erroring on the respective line because of the fact that a Next sheet does not exist after the last one...
If you want keeping the code as it is and only solve the error, please, try inserting above the problematic code line, the next one:
If J = xl.ActiveWorkbook.Worksheets.Count Then Exit For
But your code is not efficient, at all. The next part, for instance:
xl.Workbooks("P1_PCD.xlsm").Activate
xl.Sheets(1).Select
xl.Range("B1").Select
pcd_title = xl.Range("B1").value
should be replaced with the more efficient one, not involving any Activation/selection:
Dim ws As Object
Set ws = xl.Workbooks("P1_PCD.xlsm")
pcd_title = ws.Range("B1").value
Then, the way of looping between the sheets is also not efficient. Activating the sheet and selecting any range to be used only consumes Excel resources. Instead of the way you use:
For J = 1 To xl.ActiveWorkbook.Worksheets.Count
you can do it in a different, more efficient way:
Dim sh As Object
For each sh in xl.ActiveWorkbook.Worksheets
station = sh.Range("O3").Value
'your code...
'instead of
'xl.Range(c1).Select
'task = xl.ActiveCell.Value
'you should use:
task = sh.Range(c1).Value ' or better
task = sh.Range("C6").Value 'and eliminate c1 useless variable...
'it is at least strange to use
'c1 = "C" & row + 1
'xl.Range(c1).Select
'instead of directly:
sh.Range("C" & row + 1) 'selection is useless, anyhow...
Next sh
Your code is too long, you do not explain in words what you want accomplishing and I cannot spend too much time to deduce what you try doing. I am only suggesting some things necessary to be changed in order to improve the code quality and speed...
I am working on a reconciliation automation wherein I have to join multiple sheet data to produce an output. When I query single sheet without using joins it works fine, however when I join multiple sheets I get "Run-time error -2147467259 (80004005) Type mismatch in expression"
I am working on: Microsoft 365 MSO (16.0.12827.20236) 64-bit
Here is my code for reference:
Dim con As New ADODB.Connection
Function Open_Connection() As Byte
Dim strFile As String
Dim strCon As String
On Error GoTo Con_Error
strFile = ThisWorkbook.FullName
If Not con Is Nothing Then If con.State = 1 Then con.Close
strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile & ";Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"
con.Open strCon
Open_Connection = 1
Exit Function
Con_Error:
Open_Connection = 0
End Function
Private Function Supplier_Range() As String
Dim LastRow As Long
LastRow = Dump_Supplier.Range("A" & Dump_Supplier.UsedRange.Rows.Count + 1).End(xlUp).Row
If LastRow > 2 Then
Supplier_Range = Dump_Supplier.Name & "$" & Replace(Dump_Supplier.Range("A2:P" & LastRow).Address, "$", "")
End If
End Function
Private Function Client_Range() As String
Dim LastRow As Long
LastRow = Dump_Client.Range("A" & Dump_Client.UsedRange.Rows.Count + 1).End(xlUp).Row
If LastRow > 2 Then
Client_Range = Dump_Client.Name & "$" & Replace(Dump_Client.Range("A2:N" & LastRow).Address, "$", "")
End If
End Function
Function SQL_inv()
Dim Supplier_Range_txt As String
Dim Client_Range_txt As String
Supplier_Range_txt = Supplier_Range
If Len(Supplier_Range_txt) = 0 Then
MsgBox prompt:="No Data Found On " & Dump_Supplier.Name & " Sheet.", Buttons:=vbCritical, Title:="Data Not Found"
Exit Function
End If
Client_Range_txt = Client_Range
If Len(Client_Range_txt) = 0 Then
MsgBox prompt:="No Data Found On " & Dump_Client.Name & " Sheet.", Buttons:=vbCritical, Title:="Data Not Found"
Exit Function
End If
Open_Connection
If con.State = 0 Then
MsgBox prompt:="Connection With Dataset Could Not Be Opened.", Buttons:=vbCritical, Title:="Connection Failure"
Exit Function
End If
Dim strSQL As String
Dim Supplier_Inv As New ADODB.Recordset
Dim Client_Inv As New ADODB.Recordset
Dim Inv_Exact_Match As New ADODB.Recordset
Dim Inv_Match_With_Diff As New ADODB.Recordset
Dim Inv_Match_Amt As New ADODB.Recordset
Dim Inv_No_Match As New ADODB.Recordset
If Not Supplier_Inv Is Nothing Then If Supplier_Inv.State = 1 Then Supplier_Inv.Close
strSQL = "SELECT * FROM [" & Supplier_Range_txt & "] WHERE [Standard Type] LIKE ""%Invoice%"";"
strSQL = "SELECT A.[Pst DT], A.[Year], A.[Month], A.[Standard Type], A.[Type], A.[Invoice / Reference], A.[Amount], A.[Curr], A.[Debit Amount (+)], A.[Credit Amount (-)] FROM [" & Supplier_Range_txt & "] A WHERE [Standard Type] LIKE ""%Invoice%"";"
Supplier_Inv.Open Source:=strSQL, ActiveConnection:=con, CursorType:=adOpenKeyset, LockType:=adLockOptimistic
If Not Client_Inv Is Nothing Then If Client_Inv.State = 1 Then Client_Inv.Close
strSQL = "SELECT * FROM [" & Client_Range_txt & "] WHERE [Standard Type] LIKE ""%Invoice%"";"
strSQL = "SELECT B.[GL Date], B.[Year], B.[Month], B.[Standard Type], B.[Type], B.[Inv Check Num], B.[INR Amount], B.[Currency] FROM [" & Client_Range_txt & "] B WHERE [Standard Type] LIKE ""%Invoice%"";"
Client_Inv.Open Source:=strSQL, ActiveConnection:=con
Stop
If Not Inv_Exact_Match Is Nothing Then If Inv_Exact_Match.State = 1 Then Inv_Exact_Match.Close
strSQL = "SELECT A.[Pst DT], A.[Year], A.[Month], A.[Standard Type], A.[Type], A.[Invoice / Reference], A.[Amount], A.[Curr], A.[Debit Amount (+)], A.[Credit Amount (-)], " & _
"B.[GL Date], B.[Year], B.[Month], B.[Standard Type], B.[Type], B.[Inv Check Num], B.[INR Amount], B.[Currency] " & _
"FROM [" & Supplier_Range_txt & "] A " & _
"INNER JOIN [" & Client_Range_txt & "] B " & _
"ON A.[Invoice / Reference] = B.[Inv Check Num] AND A.[Standard Type] = B.[Standard Type] " & _
"WHERE A.[Standard Type] LIKE ""%Invoice%"" ;"
'AND Abs(Abs(A.[Amount]) - Abs(B.[INR Amount])) <= Home.[Amount_Diff_Tolerance].Value
Debug.Print strSQL
Inv_Exact_Match.Open Source:=strSQL, ActiveConnection:=con, CursorType:=adOpenKeyset, LockType:=adLockOptimistic
'Debug.Print Supplier_Inv.GetString
Debug.Print Inv_Exact_Match.GetString
End Function
Here is what my join query produces:
SELECT A.[Pst DT], A.[Year], A.[Month], A.[Standard Type], A.[Type], A.[Invoice / Reference], A.[Amount], A.[Curr], A.[Debit Amount (+)], A.[Credit Amount (-)], B.[GL Date], B.[Year], B.[Month], B.[Standard Type], B.[Type], B.[Inv Check Num], B.[INR Amount], B.[Currency] FROM [SOA-Supplier$A2:P25581] A INNER JOIN [SOA-Client$A2:N23548] B ON A.[Invoice / Reference] = B.[Inv Check Num] AND A.[Standard Type] = B.[Standard Type] WHERE A.[Standard Type] LIKE "%Invoice%" ;
Any help is appreciated. Thanks!
My query works fine outside of the loop when I have the hard-coded values in. When I put the query inside my loop and use variables to hold the correct values it returns EOF. I've printed out the query and run it directly in SQL server and it returns the correct results. Which makes me think my SQL syntax is ok, but I can't figure out why it doesn't return anything in the loop. Any Ideas?
Public Function getPOs()
Dim TotalPos, Curpo, Query, ClaimNum, Color, DCloc As String
Dim i As Integer
Dim Row, Style, LastRow As LongPtr
Dim ws As Worksheet
Set ws = Worksheets("test")
' Set up database connection
Dim cnn As ADODB.Connection
Dim rs As New ADODB.Recordset
Set cnn = New ADODB.Connection
cnn.ConnectionString = SQL_SERVER_CONNECTION
cnn.ConnectionTimeout = 0
cnn.CommandTimeout = 0
cnn.Open
'This query works fine, it returns results that I can iterate through.
rs.Open "SELECT PO " & _
"FROM [catalog].[dbo].[table] " & _
"WHERE CLAIM_NUMBER = '1337' AND STYLE = '293493' and COLOR = '03' AND DC_LOCATION = 'PFC'", cnn, adOpenDynamic, adLockOptimistic
' Itereate through the results
i = 0
Do While Not rs.EOF
If rs![PO] = "" Then
Exit Do
End If
If i = 0 Then
Curpo = rs![PO]
TotalPos = Curpo
Else
Curpo = rs![PO]
TotalPos = TotalPos & ", " & Curpo
End If
i = i + 1
rs.MoveNext
Loop
MsgBox TotalPos ' Works fine!
' For some reason adding the query inside this loop messes it up.
Row = 11
LastRow = ws.Cells(ws.Rows.Count, "D").End(xlUp).Row
rs.Close
While Row < 12 ' will change back to LastRow once working
'Parse the claim number
ClaimNum = Replace(ws.Cells(Row, 10), "IC - ", "")
MsgBox ClaimNum
'Style
Style = Left(ws.Cells(Row, 11), Len(ws.Cells(Row, 11)) - 2)
MsgBox Style
'Color
Color = ws.Cells(Row, 12)
MsgBox Color
'DCloc
DCloc = ws.Cells(Row, 13)
MsgBox DCloc
' When I add the query here it returns nothing...
rs.Open "SELECT PO " & _
"FROM [catalog].[dbo].[table] " & _
"WHERE CLAIM_NUMBER = " & ClaimNum & " AND STYLE = " & Style & " and COLOR = '" & Color & "' AND DC_LOCATION = ' " & DCloc & "'", cnn, adOpenDynamic, adLockOptimistic
'add the entire sql statement to the Query var so I can print it out and run it in SQL Server
Query = "SELECT PO " & _
"FROM [catalog].[dbo].[table] " & _
"WHERE CLAIM_NUMBER = " & ClaimNum & " AND STYLE = " & Style & " and COLOR = '" & Color & "' AND DC_LOCATION = '" & DCloc & "'"
' print the query... when I run this exact thing in SQL server it returns results just fine'
MsgBox Query
' iterate through results
i = 0
'rs.EOF now that it's in the loop... but why? I know the syntax of the query is correct, it returns results when I run it directly in SQL server
If rs.EOF Then
MsgBox "why???"
End If
Do While Not rs.EOF
If rs![PO] = "" Then
Exit Do
End If
If i = 0 Then
Curpo = rs![PO]
TotalPos = Curpo
Else
Curpo = rs![PO]
TotalPos = TotalPos & ", " & Curpo
End If
MsgBox TotalPos
i = i + 1
rs.MoveNext
Loop
rs.Close
Row = Row + 1
Wend
cnn.Close
End Function
rs.Open "SELECT PO " & _
"FROM [catalog].[dbo].[table] " & _
"WHERE CLAIM_NUMBER = " & ClaimNum & " AND STYLE = " & Style & " and COLOR = '" & Color & "' AND DC_LOCATION = ' " & DCloc & "'"
Don't concatenate parameter values into your SQL string - that way you don't need to care about quoting strings and worry about whether a string contains apostrophes, or worse - the widely-known tale of Little Bobby Tables captures just how impactful this careless value concatenation practice can be, if you let it.
Instead, define your query once, and let the server deal with the parameters (it's its job).
Const sql As String = _
"SELECT PO " & _
"FROM [catalog].[dbo].[table] " & _
"WHERE CLAIM_NUMBER = ? AND STYLE = ? AND COLOR = ? AND DC_LOCATION = ?"
Each ? is understood by ADODB as a positional parameter: all you need to do now, is to execute a ADODB.Command with 4 parameters, appended in the order they are specified.
Now you can write a Function that takes the values for the 4 parameters you need, and the function can return a ADODB.Recordset that contains the results - no need to redefine the SQL string every time you need it!
Private Function GetPO(ByVal cnn As ADODB.Connection, ByVal ClaimNum As String, ByVal Style As String, ByVal Color As String, ByVal DCloc As String) As ADODB.Recordset
Const sql As String = _
"SELECT PO " & _
"FROM [catalog].[dbo].[table] " & _
"WHERE CLAIM_NUMBER = ? AND STYLE = ? AND COLOR = ? AND DC_LOCATION = ?"
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
Set cmd.ActiveConnection = cnn
cmd.CommandType = adCmdText
cmd.CommandText = sql
'TODO: verify parameter types & sizes - here NVARCHAR(200).
'NOTE: parameters must be added in the order they are specified in the SQL.
cmd.Parameters.Append cmd.CreateParameter(Type:=adVarWChar, Size:=200, Value:=ClaimNum)
cmd.Parameters.Append cmd.CreateParameter(Type:=adVarWChar, Size:=200, Value:=Style)
cmd.Parameters.Append cmd.CreateParameter(Type:=adVarWChar, Size:=200, Value:=Color)
cmd.Parameters.Append cmd.CreateParameter(Type:=adVarWChar, Size:=200, Value:=DCloc)
Set GetPO = cmd.Execute
End Function
You can use it from anywhere you have an ADODB.Connection that's ready to use:
Dim rs As ADODB.Recordset
Set rs = GetPO(cnn, ClaimNum, Style, Color, DCloc)
Do While Not rs.EOF
'...
Loop
You need to wrap variables in quotes to make it work, a string type isn't enough.
"WHERE CLAIM_NUMBER = " & ClaimNum & " ...
Needs to become:
"WHERE CLAIM_NUMBER = " & "'" & ClaimNum & "'" & " ...
In addition to all the other variables you are concatenating into the SQL statement
As an aside
Dim TotalPos, Curpo, Query, ClaimNum, Color, DCloc As String
is only declaring DCloc as a string and all the others are variants.
To make them all string you need to add as string to all of them.
Dim TotalPos as string, Curpo as string, Query as string, ClaimNum as string, Color as string, DCloc As String
Newbie here.
I use Excel as a front end and Access as a back end to store data. I am trying to take a query and write the values to an Access table using VBA in Excel. I get an Either BOF or EOF is True error, and when I run the SQL statement in Access, I get records.
Any feedback would be very much appreciated. Thank you in advance.
Here is my code:
Sub Write_Timesheet_AJ()
'**********************************************JGT**********************************************
'Transpose Data for HCS
'2018.09.17
'**********************************************JGT**********************************************
strPath1 = "C:\Reports\Timesheets\"
strFile1 = "Timesheets.accdb"
strDB = strPath1 & strFile1
Conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & strDB & "; Persist Security Info=False;"
Conn.Open strDB
Conn.CursorLocation = adUseClient
'Clear table
strSQL = "Delete * From tbl_Timesheet_AJ;"
Set rs2 = Conn.Execute(strSQL)
'Transpose Data
strSQL = "Select VisitDate As VisitDt, PatientName, vw_Days_Worked_AJ.CaregiverCode As CaregiverCode, CaregiverName as AideName, CoordinatorName As Coordinator, " _
& "Street_1 As Street1, Street_2 As Street2, City1 As City, State1 as State, Zip, [Language] as L1 " _
& "From vw_Days_Worked_AJ Left Join vw_Caregiver_Info_AJ On vw_Days_Worked_AJ.CaregiverCode = vw_Caregiver_Info_AJ.CaregiverCode;"
Set rs1 = Conn.Execute(strSQL)
If rs1.RecordCount = 0 Then 'Record count check
Debug.Print strSQL
Debug.Print rs1.BOF
Debug.Print rs1.EOF
rs1.Close
Set rs1 = Nothing
Conn.Close
' MsgBox "There are no records; please check data."
Else
rs1.MoveFirst
rsCount1 = rs1.RecordCount
ReDim arrData1(rsCount1)
For loopX = 1 To rsCount1
With arrData1(loopX)
.VisitDt = Format(rs1.Fields("VisitDt"), "m/dd")
.WkEndDt = Get_Fri_Dt(CDate(rs1.Fields("VisitDt")))
.DayOfWk = Left(Get_Day_of_Wk(CDate(rs1.Fields("VisitDt"))), 3)
.PatientName = rs1.Fields("PatientName")
.CaregiverCode = rs1.Fields("CaregiverCode")
.AideName = rs1.Fields("AideName")
.Coordinator = rs1.Fields("Coordinator")
If IsNull(rs1.Fields("Street1")) Then .Street1 = " " Else .Street1 = rs1.Fields("Street1")
If IsNull(rs1.Fields("Street2")) Then .Street2 = " " Else .Street2 = rs1.Fields("Street2")
If IsNull(rs1.Fields("City")) Then .City = " " Else .City = rs1.Fields("City")
If IsNull(rs1.Fields("State")) Then .State = " " Else .State = rs1.Fields("State")
If IsNull(rs1.Fields("Zip")) Then .Zip = " " Else .Zip = rs1.Fields("Zip")
If IsNull(rs1.Fields("L1")) Then .L1 = " " Else .L1 = rs1.Fields("L1")
strInsert = "Insert Into tbl_Timesheet_AJ " _
& "(WkEndDt, PatientName, CaregiverCode, AideName, Coordinator, " & .DayOfWk & ", " _
& "AideName2, CaregiverCode2, Street1, Street2, City, State, Zip, L1) " _
& "Values (#" & .WkEndDt & "#, '" & .PatientName & "', '" & .CaregiverCode & "', " _
& "'" & .AideName & "', '" & .Coordinator & "', '" & .VisitDt & "', '" & .AideName & "', " _
& "'" & .CaregiverCode & "', '" & .Street1 & "', '" & .Street2 & "', '" & .City & "', " _
& "'" & .State & "', '" & .Zip & "', '" & .L1 & "');"
Set rs2 = Conn.Execute(strInsert)
rs1.MoveNext
End With
Next loopX
rs1.Close
Set rs1 = Nothing
Conn.Close
End If
End Sub
I've had severas problems with strings in access-vba.
The thing is, access (sometimes) limit the string's length to about 255 characters.
However, depending on HOW the string was built, it may be able to grow bigger then 255 chars.
There's an example of WORKING code :
Dim strReq as String
strReq = "SELECT exampleField1, exampleField2, exampleField3, exampleField4, exampleField5 "
strReq = strRec & ", exampleField6, exampleField7, exampleField8, .... [etc. insert many fields, you get it]"
strReq = strReq & " FROM myTable INNER JOIN Tbl2 ON ...[many JOINs as well]"
And so on, I often work with large queries so the 256 chars is easily busted.
However, these examples doesn't work :
Dim strReq as String
strReq = "SELECT exampleField1, exampleField2, exampleField3, exampleField4, exampleField5 " & _
", exampleField6, exampleField7, exampleField8, .... [etc. insert many fields, you get it]" & _
" WHERE exampleField1 = x AND exampleField2 = y AND exampleField3 = z" & _
" ORDER BY 1,2,3,4,5,6"
And this doesn't work either :
Dim strReq as String
Dim strWhere as String
strReq = "SELECT exampleField1, exampleField2, exampleField3, exampleField4, exampleField5 "
strReq = strRec & ", exampleField6, exampleField7, exampleField8, .... [etc. insert many fields, you get it]"
strWhere = "WHERE exampleField1 = x "
strWhere = strWhere & "AND exampleField2 = y"
strWhere= strWhere & " AND exampleField3 = z"
strReq = strReq & strWhere [& strJoin / strOrder / strHaving / etc]
I know know aproximatively how I can or cannot concatenate strings but I'd like to know how strings exactly work on access vba , because, i'll admit, it seems quite random so far...
*(Please note, these strings are supposed of longer length then the 255 characters AND the query is just there as an example, syntaxe mistakes or exact length in these are not the point here)
*Edit -- adding the code I'm actually using (With the working version, tried both bugging versions to clean up the code and both were bugging
strReq = "SELECT " & IIf(Len(rsRap.Fields("top")) > 0, " TOP " & rsRap.Fields("top"), "") & " " & rsRap.Fields("champs") & ", Sum([Canada]*[Quantité]) AS Montant, Sum(TblDetailCom.Quantité) AS Qty " & IIf(Len(rsRap.Fields("rep")) > 0, ", NickName", "")
strReq = strReq & " FROM (SELECT * FROM TblRepresentant WHERE RefRep not In(13,15,26,27,28)) AS TblRepresentant INNER JOIN "
strReq = strReq & " ((TblProduits LEFT JOIN TblTypBijoux ON TblProduits.Type = TblTypBijoux.IdTypBijoux) "
strReq = strReq & " INNER JOIN (TblCouleur INNER JOIN ((TblClients INNER JOIN ((TblComm LEFT JOIN RqMaxIdTrait ON TblComm.ID = RqMaxIdTrait.IdCommande) "
strReq = strReq & " LEFT JOIN TblTraitement ON RqMaxIdTrait.MaxOfIdTrait = TblTraitement.IdTrait) ON TblClients.ID = TblComm.RefClient) "
strReq = strReq & " INNER JOIN TblDetailCom ON TblComm.ID = TblDetailCom.RefCom) ON TblCouleur.ID = TblDetailCom.RefCoul) "
strReq = strReq & " ON TblProduits.IdMod = TblDetailCom.RefProd) ON TblRepresentant.RefRep = TblClients.RefRepre "
strReq = strReq & " WHERE (TblClients.RefRepre <> 5 OR (TblClients.RefRepre=5 AND TblClients.ID In (1210,219,189,578))) "
'(((TblProduits.Coll)=16) AND((TblComm.CoDatCom)>=#2011-01-01# And (TblComm.CoDatCom)<=#2014-01-01#) " 'Params Collection (16) DteDeb/fin
'strReq = strReq & " AND "
If Len(rsRap.Fields("type")) > 0 Then
strReq = strReq & " AND TblProduits.[Type] = " & rsRap.Fields("type")
End If
If Len(txtDe) > 0 Then
strReq = strReq & " AND TblTraitement.DtTrait >= #" & txtDe & "# "
End If
If Len(txtA) > 0 Then
strReq = strReq & " AND TblTraitement.DtTrait <= #" & txtA & "# "
End If
If Len(rsRap.Fields("pays")) > 0 Then
strReq = strReq & " AND TblClients.ClPaiePays = '" & rsRap.Fields("pays") & "' "
End If
If Len(rsRap.Fields("rep")) > 0 Then
strReq = strReq & " AND TblClients.RefRepre = " & rsRap.Fields("rep")
End If
If Len(rsRap.Fields("col")) > 0 Then
strReq = strReq & " AND TblProduits.Coll=" & rsRap.Fields("col")
End If
If Len(rsRap.Fields("group")) > 0 Then
strReq = strReq & " GROUP BY " & rsRap.Fields("group") & IIf(Len(rsRap.Fields("rep")) > 0, ", NickName", "")
End If
strReq = strReq & " HAVING Sum([Canada]*[Quantité]) >= 0 "
If Len(rsRap.Fields("order")) > 0 Then
strReq = strReq & " ORDER BY " & rsRap.Fields("order")
End If
You seem to accept the fact that a VBA string can contain more than 255 characters. As an example this code creates a 264 character string.
Const cstrSegment As String = "0123456789" & vbCrLf
Dim MyBigString As String
Dim i As Long
For i = 1 To 22
MyBigString = MyBigString & cstrSegment
Next
Debug.Print "Len(MyBigString): " & Len(MyBigString)
Rather you're encountering trouble based on the method you use to concatenate strings. I don't know where that trouble is exactly, but I can tell you there is a limit to the number of line continuations you can use when adding to a string. For example the following code compiles and runs without error. However if I add one more line continuation (& cstrSegment _), the compiler complains "Too many line continuations".
MyBigString = MyBigString & cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment _
& cstrSegment
If that describes the problem you're seeing, the limitation is based on line continuations, not string length. If needed, you could work around that limit by building the string in multiple steps. Do "MyBigString = MyBigString & cstrSegment _" up to the limit of line continuations, then add to MyBigString with another "MyBigString = MyBigString & cstrSegment _" block.
Make sure you're not misled by how many character you see. Perhaps the situation is you're only seeing the first 255 characters, but the string actually contains many more. That would make sense since you reported you're not getting an error building the string apparently fails.
Confirm the actual length of the string with Len():
Debug.Print "Len(MyBigString): " & Len(MyBigString)
You can also print the string's content to the Immediate window to see what it contains:
Debug.Print MyBigString
You can use Ctrl+g to open the Immediate window.
When concatenating strings for SQL, add a vbCrLf character when lines might grow long. Access seems to have trouble ingesting VBA strings (to execute as SQL) greater than about 1000 characters. e.g.
strSQL = strSQL & "SELECT some fields " & vbcrlf & "FROM some table "