Access 2010 VBA Change dates in loop - vba

I am trying to run an append query to update a table based on the first 30 records for parameters in an sql statement. All of the data resides in an Access 2010 database, and I would like to run the query based off of a button on a form.
I am new to vba and assembled the following code based off of posts.
Option Compare Database
Private Sub Command3_Click()
Dim sql As String
Dim i As Integer
Dim j As Integer
Dim rst As DAO.Recordset
Dim dbs As DAO.Database
Dim strTerritory As String
Set dbs = CurrentDb
strTerritory = "Alex Hernandez"
strSQL = "INSERT INTO tblWeather30DayMovingFinal ( NEW, RptdDate, [Clm Nbr], WeatherLimit ) SELECT TOP 30 tblWeather30DayMoving.[NEW], tblWeather30DayMoving.[RptdDate], tblWeather30DayMoving.[Clm Nbr], 1 AS WeatherLimit FROM tblWeather30DayMoving WHERE (((tblWeather30DayMoving.NEW)= strTerritory ) AND ((tblWeather30DayMoving.RptdDate) Between #" & i & "/1/" & j & "# And #" & i & "/28/" & j & "#)); "
Set rst = dbs.OpenRecordset("tblWeather30DayMoving", dbOpenTable)
With rst
For j = 2003 To 2013
For i = 1 To 12
If Not (rst.EOF And rst.BOF) Then
.MoveFirst
Do
CurrentDb.Execute strSQL
.MoveNext
Loop Until .EOF
End If
Next i
Next j
End With
Set rst = Nothing
End Sub
I receive the following error message. I am trying to figure out how to get the loop to fill my date references in the sql.
Run-time error '3075':
Syntax error in date in query expression '(((tblWeather30DayMoving.NEW)- strTerritory ) AND ((tblWeather30DayMoving.RptdDate) Between #0/1/0# And #0/28/0#)'.
Any idea how to pass i and j to the sql statement instead of the 0's that are currently showing?

You are setting the strSQL string outside of your loop.
At this point, the values of i and j are 0.
You need to assign value to strSQL inside of the second loop:
For j = 2003 To 2013
For i = 1 To 12
strSQL = "INSERT INTO tblWeather30DayMovingFinal ( NEW, RptdDate, [Clm Nbr], WeatherLimit ) SELECT TOP 30 tblWeather30DayMoving.[NEW], tblWeather30DayMoving.[RptdDate], tblWeather30DayMoving.[Clm Nbr], 1 AS WeatherLimit FROM tblWeather30DayMoving WHERE (((tblWeather30DayMoving.NEW)= strTerritory ) AND ((tblWeather30DayMoving.RptdDate) Between #" & i & "/1/" & j & "# And #" & i & "/28/" & j & "#)); "
If Not (rst.EOF And rst.BOF) Then
.MoveFirst
Do
CurrentDb.Execute strSQL
.MoveNext
Loop Until .EOF
End If
Next i
Next j

I did it in notepad and not tested, but here is the idea:
Option Compare Database
option explicit
Private Sub Command3_Click()
Dim sql As String, sql2 as string
Dim i As Integer
Dim j As Integer
Dim rst As DAO.Recordset
Dim dbs As DAO.Database
Dim strTerritory As String
Set dbs = CurrentDb
strTerritory = "Alex Hernandez"
sql = "INSERT INTO tblWeather30DayMovingFinal ( NEW, RptdDate, [Clm Nbr], WeatherLimit ) " & _
"SELECT TOP 30 tblWeather30DayMoving.[NEW], tblWeather30DayMoving.[RptdDate], tblWeather30DayMoving.[Clm Nbr], 1 AS WeatherLimit " & _
"FROM tblWeather30DayMoving WHERE (((tblWeather30DayMoving.NEW)= strTerritory ) AND ((tblWeather30DayMoving.RptdDate) Between #mm/01/yyyy# And #mm/28/yyyy#)); "
Set rst = dbs.OpenRecordset("tblWeather30DayMoving", dbOpenTable)
With rst
For j = 2003 To 2013
For i = 1 To 12
If Not (rst.EOF And rst.BOF) Then
.MoveFirst
Do
sql2 = replace(1, sql,"yyyy", cstr(j)) 'replace "jjjj" by year
sql2 = replace(1,sql2,"mm", format(i,"00")) 'replace "mm" by month
debug.print sql2
CurrentDb.Execute sql2 'this can be REM'd once it is all working
.MoveNext
Loop Until .EOF
End If
Next i
Next j
End With
Set rst = Nothing
End Sub
Also note that you did not set Option Explicit, and you are mixing variable names between strSql and Sql.
I created the sql string using silly dates, and then replaced them by the appropriate figues in the loop, just before execution. Not the most efficient, but I find it easy and readable.

Related

Access vba how to run code to whole table

I have table named schedules where I should change values of some field depending value of another field
I manage to do that running code on form (record by record) but now I like to run it outside of form
because of mass import to database - Is it possible?
Here is part of my code:
If Not IsNumeric(DAY_0_DEST_0_NAME) Then
DAY_0_TYPE_0_OSP = 1
Else: DAY_0_TYPE_0_OSP = 3
End If
If Nz(DAY_0_DEST_0_NAME) = "" Then
DAY_0_TYPE_0_OSP = 0
End If
If Not IsNumeric(DAY_0_DEST_1_NAME) Then
DAY_0_TYPE_1_OSP = 1
Else: DAY_0_TYPE_1_OSP = 3
End If
If Nz(DAY_0_DEST_1_NAME) = "" Then
DAY_0_TYPE_1_OSP = 0
End If
Possibly the easiest way to do this is to run some update SQL statements from a VBA procedure. And because you are altering two pairs of fields, you can do this in a small loop:
Sub sUpdateData()
Dim db As DAO.Database
Dim strSQL As String
Dim lngLoop1 As Long
Set db = DBEngine(0)(0)
For lngLoop1 = 0 To 1
db.Execute "UPDATE Table1 SET DAY_0_TYPE_" & lngLoop1 & "_OSP=3 WHERE IsNumeric(DAY_0_DEST_" & lngLoop1 & "_NAME)=True;"
db.Execute "UPDATE Table1 SET DAY_0_TYPE_" & lngLoop1 & "_OSP=1 WHERE IsNumeric(DAY_0_DEST_" & lngLoop1 & "_NAME)=False;"
db.Execute "UPDATE Table1 SET DAY_0_TYPE_" & lngLoop1 & "_OSP=0 WHERE DAY_0_DEST_" & lngLoop1 & "_NAME IS NULL;"
Next lngLoop1
Set db = Nothing
End Sub
Regards,

Excel VBA - writing Data from SQL/Recordset very slow

I am trying to write SQL Server data to an Excel sheet but it is very slow. Is there something to optimize? Approximately, 4000 entries at 20 cColumns takes 6-7 minutes.
Database ("freigabe") Module: Connecting to Database and get RecordSet
(this works like a charm)
Private Function ConnectSQL() As ADODB.Connection
Set conn = New ADODB.Connection
conn.ConnectionString = "DRIVER={SQL Server};" _
& "SERVER=xxxxx;" _
& " DATABASE=xxxxx;" _
& "UID=xxxxxx;PWD=xxxxx; OPTION=3"
conn.Open
Set ConnectSQL = conn
End Function
Public Function load(Optional ByVal FieldName As String = "", Optional ByVal fieldValue As String = "", Optional ByVal ComparisonOperator As String = "=")
'wenn fehler return?
'-> Über errorhandler retun rs oder boolen
Dim rs As New ADODB.Recordset
Dim sql As String
Dim contition As String
contition = " "
Dim sqlfrom As String
Dim sqlto As String
On Error GoTo Fehler:
sql = "SELECT * FROM " & TBLNAME & " WHERE storno='0' AND created BETWEEN '2020-02-01' AND '2020-02-15'"
Set conn = ConnectSQL()
rs.Open sql, conn, adOpenStatic
Set load = rs
Exit Function
End If
Fehler:
load = Err.Description
End Function
Get/Write: Build a connection and retrieving recordset. The While loop is taking long. I am skipping text-rich columns (it gets faster but still too long). Showing a load-window so the person doesn't think that Excel "isn't working". After that, the data get's validated (not included).
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim rs As Recordset
Dim k As Integer
Dim i As Integer
Dim startt As Double
Dim endt As Double
Dim rngDst As Range
Set rs = freigabe.load()
Set rngDst = Worksheets("Freigaben").Range("G2")
With Worksheets("Freigaben").Range("g2:Z50000")
.ClearContents
'.CopyFromRecordset rs
End With
Count = rs.RecordCount
k = 0
gui_laden.Show
startt = Timer
With rs
If Not .BOF And Not .EOF Then
.MoveLast
.MoveFirst
While Not .EOF
For i = 0 To .Fields.Count - 1
If i <> 13 And i <> 2 And i <> 10 And i <> 5 And i <> 6 And i <> 0 Then rngDst.Offset(, i) = .Fields(i).Value 'skip unneccessary data and write
Next i
k = k + 1
Debug.Print k & "/" & Count
gui_laden.lbl_status = "Lade Daten herunter: " & k & "/" & Count
gui_laden.Repaint
.MoveNext
DoEvents 'Ensure Application doesn't freeze
Set rngDst = rngDst.Offset(1)
Wend
End If
End With
endt = Timer - startt
Debug.Print "Dauer: " & endt
What I tried:
CopyFromRecordSet -> Application freezes
Test in new workbook -> same
Thank you very much!

Write an SQL query selecting data from filtered Date columns

i am trying to query a crosstab table/recordset in Access (tried ADO on excel sheet), where the columns are having dates in them e.g.
if i want to pull a limited data having columns only for the Year 2014, how do i write such a query? Please note, these columns may vary.
something like this, there may be a simpler method though
Sub Akward_Query()
Dim strSQL As String
Dim strSQL2 As String
Dim rst As ADODB.Recordset
Dim fld As ADODB.Field
Dim intYear As Integer
intYear = 2014
strSQL = "Select top 1 * from tbl_Test"
Set rst = New ADODB.Recordset
rst.Open strSQL, CurrentProject.Connection, 1
strSQL2 = "Select "
For Each fld In rst.Fields
If InStr(1, fld.Name, "Week Ending") > 0 And InStr(1, fld.Name, intYear)>0 Then
strSQL2 = strSQL2 & "[" & fld.Name & "],"
End If
Next fld
If Right(strSQL2, 1) = "," Then strSQL2 = Left(strSQL2, Len(strSQL2) - 1)
strSQL2 = strSQL2 & " from tbl_Test"
End Sub

Speeding up a ms access sql query from excel

I have the code below and it seems to be taking a while to open the recordset and run the query attached (62 seconds to be exact). While 1 minute is fine, when I need to do this 13 times, it begins to take a long time to run the code.
I've debugged the code down to just the opening of the recordset taking the longest time.
My question is: Is there a method to run this faster? (i'm connecting to MS Access 2013 from Excel 2013)
Thanks in advance,
Rich
Sub GetUnits2()
'Declaring the necessary variables.
Dim con As Object
Dim rs As Object
Dim AccessFile As String
Dim strTable As String
Dim SQL As String
Dim myValues() As Variant
Dim i As Long
Dim k As Long
Dim j As Integer
Dim SheetName As String
Dim WeekNumber As Long
Dim year As Long
Dim Model1 As String
Dim Model2 As String
Dim xlrow As Integer
Dim xlcol As Integer
SheetName = "Sheet2"
Sheets(SheetName).Select
Model1 = Sheets(SheetName).Cells(3, 2).Value
Model2 = Sheets(SheetName).Cells(4, 2).Value
'Disable screen flickering.
Application.ScreenUpdating = False
'Specify the file path of the accdb file. You can also use the full path of the file like:
AccessFile = "C:\Users\rich.wolff\Desktop\2014POSDatabase\HMKPOSDatabase2014.accdb"
On Error Resume Next
'Create the ADODB connection object.
Set con = CreateObject("ADODB.connection")
'Check if the object was created.
If Err.Number <> 0 Then
MsgBox "Connection was not created!", vbCritical, "Connection error"
Exit Sub
End If
On Error GoTo 0
'Open the connection.
con.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & AccessFile
'Set Current Week, Year, & Starting Cell
WeekNumber = Sheets(SheetName).Cells(8, 14).Value
year = Sheets(SheetName).Cells(9, 14).Value
xlcol = 14 'Starting Column
xlrow = 11 'Starting Row
'Open Query Loop
For k = 1 To 1
SQL = "SELECT Sum(StoreSalesData.QTY) AS Units"
SQL = SQL & " FROM VSNConversionData INNER JOIN ([Sleepys Store List] INNER JOIN StoreSalesData ON [Sleepys Store List].[Store Code] = StoreSalesData.STR) ON VSNConversionData.VSN = StoreSalesData.VSN"
SQL = SQL & " WHERE (((VSNConversionData.VSNStyle)='" & Model2 & "') AND ((StoreSalesData.WeekNum)=" & WeekNumber & ") AND ((StoreSalesData.Year)=" & year & ") AND ((StoreSalesData.STR) In (SELECT FloorModels2.[Source Org]"
SQL = SQL & " FROM FloorModels2"
SQL = SQL & " WHERE (((FloorModels2.[Source Org]) In (SELECT FloorModels2.[Source Org]"
SQL = SQL & " FROM FloorModels2"
SQL = SQL & " WHERE (((FloorModels2.WeekNumber)=" & WeekNumber & ") AND ((FloorModels2.Year)=" & year & ") AND ((FloorModels2.VSNStyle)='" & Model1 & "')))) AND ((FloorModels2.WeekNumber)=" & WeekNumber & ") AND ((FloorModels2.Year)=" & year & ") AND ((FloorModels2.VSNStyle)='" & Model2 & "')))));"
On Error Resume Next
'Create the ADODB recordset object.
Set rs = CreateObject("ADODB.recordset")
'Check if the object was created.
If Err.Number <> 0 Then
Set rs = Nothing
Set con = Nothing
MsgBox "Connection was not created!", vbCritical, "Connection error"
Exit Sub
End If
On Error GoTo 0
'Set thee cursor location.
rs.CursorLocation = 3 'adUseClient on early binding
rs.CursorType = 1 'adOpenKeyset on early binding
'Open the recordset.
rs.Open SQL, con
'Redim the table that will contain the filtered data.
ReDim myValues(rs.RecordCount)
If Not (rs.EOF And rs.BOF) Then
rs.MoveFirst
Dim dbcol As Integer
dbcol = 0
Worksheets(SheetName).Cells(xlrow, xlcol).ClearContents
Worksheets(SheetName).Cells(xlrow, xlcol).Value = rs(dbcol).Value
Else
rs.Close
con.Close
Set rs = Nothing
Set con = Nothing
Application.ScreenUpdating = True
MsgBox "There are no records in the recordset!", vbCritical, "No Records"
Exit Sub
End If
'Close the recordet
rs.Close
Set rs = Nothing
If WeekNumber = 1 Then
year = year - 1
WeekNumber = 52
Else
year = year
WeekNumber = WeekNumber - 1
End If
' Next Column
xlcol = xlcol - 1
Next
'End Query Loop
con.Close
Set rs = Nothing
Set con = Nothing
Application.ScreenUpdating = True
End Sub
Have I wandered accidentally into a PHP forum?
Declare the ADODB libraries using tools:references - they will run faster, you get intellisense and a listing of all the available properties and options in the Object Browser, and you gain the ability to run the query asynchronously.
That's Early-Binding, an improvement on Late-Binding.
Next, open the Recordset object with dbForwardOnly (slightly faster) and dump it into a VBA array variant with the Recordset.GetRows method: transpose the array in your code, and write it to the range.
I can see that you've made progress on optmising the SQL: try saving it as a parameter query in the database. The ADODB.Command object can open a named query, populate the parameters, and return a recordset - the query itself may or may not run faster, but the lead time to parse the SQL will be significantly faster.
You could try:
Sub M_snb()
c00 = "C:\Users\rich.wolff\Desktop\2014POSDatabase\HMKPOSDatabase2014.accdb"
With Sheets("sheet2")
sn = Array(.Cells(3, 2), .Cells(4, 2), .Cells(8, 14), .Cells(9, 14)) ' model 1, model 2, weeknumber, year
End With
For j = 1 To 13
c01 = "SELECT Sum(StoreSalesData.QTY) AS Units"
c01 = c01 & " FROM VSNConversionData INNER JOIN ([Sleepys Store List] INNER JOIN StoreSalesData ON [Sleepys Store List].[Store Code] = StoreSalesData.STR) ON VSNConversionData.VSN = StoreSalesData.VSN"
c01 = c01 & " WHERE (((VSNConversionData.VSNStyle)='" & sn(1) & "') AND ((StoreSalesData.WeekNum)=" & sn(2) & ") AND ((StoreSalesData.Year)=" & sn(3) & ") AND ((StoreSalesData.STR) In (SELECT FloorModels2.[Source Org]"
c01 = c01 & " FROM FloorModels2"
c01 = c01 & " WHERE (((FloorModels2.[Source Org]) In (SELECT FloorModels2.[Source Org]"
c01 = c01 & " FROM FloorModels2"
c01 = c01 & " WHERE (((FloorModels2.WeekNumber)=" & sn(2) & ") AND ((FloorModels2.Year)=" & sn(3) & ") AND ((FloorModels2.VSNStyle)='" & sn(0) & "')))) AND ((FloorModels2.WeekNumber)=" & sn(2) & ") AND ((FloorModels2.Year)=" & sn(3) & ") AND ((FloorModels2.VSNStyle)='" & sn(1) & "')))));"
With CreateObject("ADODB.recordset")
.Open c01, "Provider=Microsoft.Jet.OLEDB.12.0;Data Source=" & c00
Sheets("sheets2").Cells(11, 14 + j).CopyFromRecordset .DataSource
End With
Next
End Sub

VBA to insert many records into access DB fast

OK so I have a spreadsheet that produces a reasonably large amount of records (~3500)
I have the following script that inserts them into my access db:
Sub putinDB()
Dim Cn As ADODB.Connection, Rs As ADODB.Recordset
Dim MyConn, sSQL As String
Dim Rw As Long, c As Long
Dim MyField, Result
Dim x As Integer
Dim accName As String, AccNum As String, sector As String, holding As String, holdingvalue As Double, holdingdate As Date
theend = lastRow("Holdings", 1) - 1
'Set source
MyConn = "S:\Docs\Harry\Engine Client\Engine3.accdb"
'Create query
Set r = Sheets("Holdings").Range("a2")
x = 0
Do
Application.StatusBar = "Inserting record " & x + 1 & " of " & theend
accName = r.Offset(x, 0)
AccNum = r.Offset(x, 4)
sector = r.Offset(x, 2)
holding = r.Offset(x, 1)
holdingvalue = r.Offset(x, 3)
holdingdate = r.Offset(x, 5)
sSQL = "INSERT INTO Holdings (AccName, AccNum, Sector, Holding, HoldingValue, HoldingDate)"
sSQL = sSQL & " VALUES ('" & Replace(accName, "'", "''") & "', '" & AccNum & "', '" & sector & "', '" & Replace(holding, "'", "''") & "', '" & holdingvalue & "', #" & holdingdate & "#)"
Debug.Print (sSQL)
'Create RecordSet
Set Cn = New ADODB.Connection
With Cn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.CursorLocation = adUseClient
.Open MyConn
Set Rs = .Execute(sSQL)
End With
x = x + 1
Loop While r.Offset(x, 0) <> "" Or x < 15
Application.StatusBar = False
End Sub
The trouble is, is that it loops through each record one-by-one, rebuilds and executes the query each time which results in very slow execution (about 2-3 records per second on my PC)
Is there a way to have vba insert the whole range into the DB in one go without having to loop through?
Thanks
The answer you have provided should improve things slightly as you only need open the connection once, but the code is still inefficient. You really only want to write to your recordset once with all the data rather than like this. I always prefer working from the Access side to pull info from Excel as oppose to pushing into Access from Excel but I believe we can use either for this scenario.
In this case your better to use DAO over ADO and work with a Transacation, essentially you still loop over the recordset but the actual act of writing the data does not happen until you Commit at the end so it's much faster.
This is a very basic example from the Access side for you to try:
Private Sub TestTrans()
Dim wksp As DAO.Workspace
Dim rs As DAO.Recordset
Set wksp = DBEngine.Workspaces(0) 'The current database
wksp.BeginTrans 'Start the transaction buffer
Set rs = CurrentDb.OpenRecordset("Table1", dbOpenDynaset)
Do 'Begin your loop here
With rs
.AddNew
!Field = "Sample Data"
.Update
End With
Loop 'End it here
wksp.CommitTrans 'Commit the transaction to dataset
End Sub
OK, silly me. After a bit of tinkering it turns out that putting the
Set Cn = New ADODB.Connection
With Cn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.CursorLocation = adUseClient
.Open MyConn
End With
bit outside the loop makes it far quicker.