Is ther a Join function in vba to combine multiple fields rather than using concatenate function in access? - vba

Thank you to all your responses.
I have a table with one id field and R1-R30 fields.
I was able to concatenate R1-R30 fields in a query using
Route: Trim([R1] & IIf([R2]="",""," ") & [R2] & IIf([R3]="",""," ") & [R3] & IIf([R4]="",""," ") & [R4] & IIf([R5]="",""," ") & [R5] & IIf([R6]="",""," ") & [R6] & IIf([R7]="",""," ") & [R7] & IIf([R8]="",""," ") & [R8] & IIf([R9]="",""," ") & [R9] & IIf([R10]="",""," ") & [R10] & IIf([R11]="",""," ") & [R11] & IIf([R12]="",""," ") & [R12] & IIf([R13]="",""," ") & [R13] & IIf([R14]="",""," ") & [R14] & IIf([R15]="",""," ") & [R15] & IIf([R16]="",""," ") & [R16] & IIf([R17]="",""," ") & [R17] & IIf([R18]="",""," ") & [R18] & IIf([R19]="",""," ") & [R19] & IIf([R20]="",""," ") & [R20] & IIf([R21]="",""," ") & [R21] & IIf([R22]="",""," ") & [R22] & IIf([R23]="",""," ") & [R23] & IIf([R24]="",""," ") & [R24] & IIf([R25]="",""," ") & [R25] & IIf([R26]="",""," ") & [R26] & IIf([R27]="",""," ") & [R27] & IIf([R28]="",""," ") & [R28] & IIf([R29]="",""," ") & [R29] & IIf([R30]="",""," ") & [R30])
My question is if the Join function I found can be applied to a query where the delimeter could be a spare, comma or slash.
Join (source_array,[delimiter])
Thanks

This would be the code to take all values of 1 single recordset into a bidimensional array, and then take those values into a unidimensional array (excluding null values, because null values cannot be joined with JOIN).
I think it would be better just looping trough every field with the loop, but in case it might help, i'll post it.
To replicate your issue, I just created a database with 1 single table with 2 records:
I'll concatenate all fields, excluding ID field. So with an easy query, I can get a recordset of 1 single record, using ID field as parameter:
SELECT Tabla1.Field1, Tabla1.Field2, Tabla1.Field3, Tabla1.Field4
FROM Tabla1
WHERE (((Tabla1.Id)=1));
And then the VBA code to Msgbox the fields joined, using a comma as delimiter.
Sub JOIN_RST()
Dim rst As Recordset
Dim vArray As Variant
Dim SingleArray() As Variant
Dim i As Long
Dim MySQL As String
Dim STRJoined As String
MySQL = "SELECT Tabla1.Field1, Tabla1.Field2, Tabla1.Field3, Tabla1.Field4 " & _
"FROM Tabla1 WHERE (((Tabla1.Id)=2));" 'query to get a single recordset.
Set rst = Application.CurrentDb.OpenRecordset(MySQL, 2, 4)
DoEvents
If rst.RecordCount > 0 Then
rst.MoveLast
rst.MoveFirst
vArray = rst.GetRows
ReDim SingleArray(UBound(vArray))
For i = 0 To UBound(SingleArray)
If IsNull(vArray(i, 0)) = True Then
SingleArray(i) = ""
Else
SingleArray(i) = vArray(i, 0)
End If
Next i
Debug.Print vArray(0, 0) 'Field 1
Debug.Print vArray(1, 0) 'Field 2
Debug.Print vArray(2, 0) 'Field 3
Debug.Print vArray(3, 0) 'Field 4
STRJoined = Join(SingleArray, ",")
Debug.Print STRJoined
End If
Set rst = Nothing
Erase vArray
Erase SingleArray
DoEvents
End Sub
If I execute this code using as WHERE parameter ID=1 , in debugger Window I get:
First Record
1
Null
My first record. Got a null value in Field 3 (it's empty)
First Record,1,,My first record. Got a null value in Field 3 (it's empty)
With ID=2 I get:
Second Record
2
Not null
Second Record
Second Record,2,Not null,Second Record
So this kinda works. I hope you can adapt it to your needs. but as i said. looking at the code, I think it would be easier just looping trough fields in a single query with all records. something like this:
Sub LOOPING_TROUGHT_FIELDS()
Dim RST As Recordset
Dim Joined_Records() As Variant
Dim i As Long
Dim MySQL As String
Dim STRJoined As String
Dim FLD As Field
MySQL = "SELECT Tabla1.Field1, Tabla1.Field2, Tabla1.Field3, Tabla1.Field4 " & _
"FROM Tabla1;" 'query to get all recordset you want to join
Set RST = Application.CurrentDb.OpenRecordset(MySQL, 2, 4)
DoEvents
If RST.RecordCount > 0 Then
RST.MoveLast
RST.MoveFirst
i = 0
ReDim Joined_Records(RST.RecordCount)
Do Until RST.EOF = True
For Each FLD In RST.Fields
If IsNull(FLD.Value) = True Then
STRJoined = STRJoined & "" & ","
Else
STRJoined = STRJoined & FLD.Value & ","
End If
Next FLD
Joined_Records(i) = Left(STRJoined, Len(STRJoined) - 1) 'we get 1 minus because there is an extra comma at end
i = i + 1
STRJoined = ""
RST.MoveNext
Loop
End If
Set RST = Nothing
Set FLD = Nothing
For i = 0 To UBound(Joined_Records) Step 1
Debug.Print Joined_Records(i)
Next i
Erase Joined_Records
End Sub
I don't know how many records you got. Try both and check how long does each option takes, and then choose 1.
Hope you can adapt all this to your needs. Welcome to SO.

Related

Getting ODBC - System Resources Exceeded (Rutime error 3035)

Need some assistance. I took Gord Thompson's code here How to increase performance for bulk INSERTs to ODBC linked tables in Access? and modified it to fit my case.
I am trying to copy the contents of a query called 'bulk_insert' (which is based on a local table in MS Access DB) into a SQL linked table called dbo_tblCVR_Matching_tmp. The query has no calculated fields or functions or nothing, just 102 columns of plain data. I'm currently testing with files in the range of 6K to 10K records.
The code executes and it copies many records over before I get the error in the title of this thread. I have looked around, but there is nothing that would help me with my particular issue. Not sure if I have to clear or refresh something. Here is the 2 routines I'm using:
'==============================================================
'Gord Thompson Stackoverflow: https://stackoverflow.com/questions/25863473/how-to-increase-performance-for-bulk-inserts-to-odbc-linked-tables-in-access
'==============================================================
Sub bulk_insert()
Dim cdb As DAO.Database
Dim rst As DAO.Recordset
Dim t0 As Single
Dim i As Long
Dim c As Long
Dim valueList As String
Dim separator As String
Dim separator2 As String
t0 = Timer
Set cdb = CurrentDb
Set rst = cdb.OpenRecordset("SELECT * FROM bulk_insert", dbOpenSnapshot)
i = 0
valueList = ""
separator = ""
Do Until rst.EOF
i = i + 1
valueList = valueList & separator & "("
separator2 = ""
For c = 0 To rst.Fields.Count - 1
valueList = valueList & separator2 & "'" & rst.Fields(c) & "'"
If c = 0 Then
separator2 = ","
End If
Next c
valueList = valueList & ")"
If i = 1 Then
separator = ","
End If
If i = 1000 Then
SendInsert valueList
i = 0
valueList = ""
separator = ""
End If
rst.MoveNext
Loop
If i > 0 Then
SendInsert valueList
End If
rst.Close
Set rst = Nothing
Set cdb = Nothing
Debug.Print "Elapsed time " & Format(Timer - t0, "0.0") & " seconds."
End Sub
'==============================================================
Sub SendInsert(valueList As String)
Dim cdb As DAO.Database
Dim qdf As DAO.QueryDef
Set cdb = CurrentDb
Set qdf = cdb.CreateQueryDef("")
qdf.Connect = cdb.TableDefs("dbo_tblCVR_Matching_tmp").Connect
qdf.ReturnsRecords = False
qdf.sql = "INSERT INTO dbo.tblCVR_Matching_tmp (" & _
"Associate_Id , Recd_Date, Price_Sheet_Eff_Date, VenAlpha, Mfg_Name, Mfg_Model_Num, Fei_Alt1_Code, Mfg_Product_Num, Base_Model_Num, Product_Description," & _
"Qty_Base_UOM , Price_Invoice_UOM, Mfr_Pub_Sugg_List_Price, Mfr_Net_Price, IMAP_Pricing, Min_Order_Qty, UPC_GTIN, Each_Weight, Each_Length, Each_Width," & _
"Each_Height, Inner_Pack_GTIN_Num, Inner_Pack_Qty, Inner_Pack_Weight, Inner_Pack_Length, Inner_Pack_Width, Inner_Pack_Height, Case_GTIN_Num, Case_Qty," & _
"Case_Weight, Case_Length, Case_Width, Case_Height, Pallet_GTIN_Num, Pallet_Qty, Pallet_Weight, Pallet_Length, Pallet_Width, Pallet_Height, Pub_Price_Sheet_Eff_Date," & _
"Price_Sheet_Name_Num, Obsolete_YN, Obsolete_Date, Obsolete_Stock_Avail_YN, Direct_Replacement, Substitution, Shelf_Life_YN, Shelf_Life_Time, Shelf_Life_UOM," & _
"Serial_Num_Req_YN, LeadLaw_Compliant_YN, LeadLaw_3rd_Party_Cert_YN, LeadLaw_NonPotable_YN, Compliant_Prod_Sub, Compliant_Prod_Plan_Ship_Date, Green, GPF, GPM," & _
"GPC, Freight_Class, Gasket_Material, Battery_YN, Battery_Type, Battery_Count, MSDS_YN, MSDS_Weblink, Hazmat_YN, UN_NA_Num, Proper_Shipping_Name," & _
"Hazard_Class_Num, Packing_Group, Chemical_Name, ORMD_YN, NFPA_Storage_Class, Kit_YN, Load_Factor, Product_Returnable_YN, Product_Discount_Category," & _
"UNSPSC_Code, Country_Origin, Region_Restrict_YN, Region_Restrict_Regulations, Region_Restrict_States, Prop65_Eligibile_YN, Prop65_Chemical_Birth_Defect," & _
"Prop65_Chemical_Cancer, Prop65_Chemical_Reproductive, Prop65_Warning, CEC_Applicable_YN, CEC_Listed_YN, CEC_Model_Num, CEC_InProcess_YN, CEC_Compliant_Sub," & _
"CEC_Compliant_Sub_Cross_YN, Product_Family_Name, Finish, Kitchen_Bathroom, Avail_Order_Date, FEI_Exclusive_YN, MISC1, MISC2, MISC3" & _
") Values " & valueList
'this is the line that is always highlighted when the error occurs
qdf.Execute dbFailOnError
Set qdf = Nothing
Set cdb = Nothing
End Sub
This is the final version of the code after testing it a million times, just in case someone runs into my same issue. Again thx to Albert Kallal for helping me out on this.
I added some comments in the code as well as additional information to get this thing working on one go.
In my case,
I took care of any duplicates before querying the records (i.e. I created an append query to copy the records to a local table with a primary key)
Created a pass through query 'p'
Used a function to help me escape chars such as the single quote char and deal with nulls and blanks
Integrated a dlookup function to prevent me from going crazy on hard coding the names of every column on my query. Also to allow filtering of empty columns to maximize the use of the chunk size
' =============================================================
' Credit to Albert Kallal Getting ODBC - System Resources Exceeded (Rutime error 3035)
' =============================================================
Sub bulk_insert()
Dim rstLocal As DAO.Recordset
Set rstLocal = CurrentDb.OpenRecordset("bi") 'bi is the name of the query I'm using to list of the records in the bulk
Dim sBASE As String ' base sql insert string
Dim sValues As String ' our values() list built up
Dim t As Single
t = Timer
Dim i As Long
Dim j As Long
Dim c As Long
Dim ChunkSize As Long ' # length size of "text" to send to server
Dim separator2 As String
Dim potentialHeader As String
Dim test
Dim filledArray() As Long
ChunkSize = 48000 'chunk size / or number of chars
'Try to programmatically create the insert, we will also remove anything that doesn't have values
With rstLocal
If Not rstLocal.EOF Then
sBASE = "INSERT INTO dbo.tblCVR_Matching_tmp (" 'this is where I added my SQL table
ReDim filledArray(0 To .Fields.Count - 1)
separator2 = ""
For c = 0 To .Fields.Count - 1 'using loop to get all the headers in my query
potentialHeader = .Fields(c).Name
test = DLookup(potentialHeader, "bi", potentialHeader & " is not null") 'using the dlookup function to isolate headers from my query that have values in its column
If test <> "" Then
filledArray(c) = 1
sBASE = sBASE & separator2 & potentialHeader
separator2 = ","
Else
filledArray(c) = 0
End If
Next c
sBASE = sBASE & ") VALUES "
End If
End With
Dim RowsInChunk As Long ' this will show rows that fit into a chunk
Dim RowCountOut As Long
sValues = ""
Do While rstLocal.EOF = False
RowCountOut = RowCountOut + 1
If sValues <> "" Then sValues = sValues & ","
RowsInChunk = RowsInChunk + 1
sValues = sValues & "("
separator2 = ""
With rstLocal
For c = 0 To .Fields.Count - 1
If filledArray(c) = 1 Then
sValues = sValues & separator2 & sql_escape(.Fields(c)) 'using sql_escape function for cells that have 'null' or single quotes... the function helps escape the characters to avoid getting errors on the insert
separator2 = ","
Else
'SKIP IF ALL NULLS
End If
Next c
End With
sValues = sValues & ")"
If (Len(sBASE) + Len(sValues)) >= ChunkSize Then
'send data to server
With CurrentDb.QueryDefs("p")
.sql = sBASE & sValues
.Execute
End With
Debug.Print "Rows in batch = " & RowsInChunk 'displays the number of rows per batch sent on each bulk insert statement
RowsInChunk = 0
sValues = ""
DoEvents
End If
rstLocal.MoveNext
Loop
' send out last batch (if any)
If sValues <> "" Then
With CurrentDb.QueryDefs("p") 'using pass through query here. I named mine 'p'
.sql = sBASE & sValues
.Execute
End With
sValues = ""
End If
rstLocal.Close
t = Timer - t
Debug.Print "done - time = " & t 'displays information on the immediate window as to the total duration of the sub
End Sub
====this is the sql_escape function========
' detects if a values is string or null and properly escapes it
Public Function sql_escape(val As Variant)
If LCase(val) = "null" Or val = "" Or IsNull(val) Then
sql_escape = "NULL"
Else
' also need to escape "'" for proper sql
val = Replace(val, "'", "''")
sql_escape = "'" & val & "'"
End If
End Function
In your loop, put in a test for the value length.
I would trigger the insert at about 4000 characters, maybe try 8000.
Also, you want to use a pass-though query for this, else it will be slow.
So, the code will be say like you have, but make sure the output format is in t-sql (sql server) format, and not JET/ACE sql format.
Note that sql server DOES have a short hand for inserts, and we WANT to use that fact since this reduces the overhead (the sql syntax) by a large amount (and looking at your code, you DO seem to be doing this).
So, the formart we want is this:
INSERT INTO tblBig (ID, FirstName, LastName, City)
VALUES (134, 'Albert', 'Kallal', 'Edmonton'),
VALUES (134, 'Albert', 'Kallal', 'Edmonton'),
VALUES (134, 'Albert', 'Kallal', 'Edmonton');
Note how we only need ONE insert command for many rows.
So, our code stub will look like this:
Sub TestAppendNeedForSpeed()
' I wanted to allow PK inserts
With CurrentDb.QueryDefs("qryPass1")
.SQL = "SET IDENTITY_INSERT TBLbIG1 ON;"
.Execute
End With
Dim rstLocal As dao.Recordset
Set rstLocal = CurrentDb.OpenRecordset("tblBig")
Dim sBASE As String ' base sql insert string
Dim sValues As String ' our values() list built up
Dim t As Single
t = Timer
Dim i As Long
Dim j As Long
Dim ChunkSize As Long ' # length size of "text" to send to server
ChunkSize = 4000 ' I don't think going higher will help
sBASE = "INSERT INTO tblBig1 (ID,FirstName,LastName,City) VALUES "
Dim RowsInChunk As Long ' this will show rows that fit into a chunk - only FYI
Dim RowCountOut As Long
sValues = ""
Do While rstLocal.EOF = False
RowCountOut = RowCountOut + 1
If sValues <> "" Then sValues = sValues & ","
RowsInChunk = RowsInChunk + 1
With rstLocal
sValues = sValues & "(" & !ID & "," & qu(!FirstName) & "," & qu(!LastName) & "," & qu(!City) & ")"
End With
If (Len(sBASE) + Len(sValues)) >= ChunkSize Then
' send data to server
With CurrentDb.QueryDefs("qryPass1")
.SQL = sBASE & sValues
.Execute
End With
Debug.Print "(" & RowCount & ") -- buffer out - " & RowsInChunk
RowsInChunk = 0
sValues = ""
DoEvents
End If
rstLocal.MoveNext
Loop
' send out last batch (if any)
If sValues <> "" Then
With CurrentDb.QueryDefs("qryPass1")
.SQL = sBASE & sValues
.Execute
End With
sValues = ""
End If
rstLocal.Close
t = Timer - t
Debug.Print "done - time = " & t
End Sub
So, the way we have this laid out, we can set/tweak/test/try the best chunk size.
You not even close and in the same ball part to insert 4000 rows at a time. Try about 4000 characters, maybe 8000. Some systems, I seen about 12000 char chunk size work best.
And as noted, use the above pass-though query idea - it will also run MUCH faster.
You can expect about 15x to 20x speed improvement with above. So, in place of say 120 minutes, you see about 6 minutes of time.
So, use the above template and approach. Of course the ONE row of values could be an external sub (or function) call, but the above approach will get you the best speed.

Microsoft Office Access - Median function - Too few parameters

I am trying to use this code to calculate median from my query which has these criteria:
<[Form]![testForm2]![crit1] And >[Form]![testForm2]![crit2] and <[Form]![testForm2]![Age1] And >[Form]![testForm2]![Age2]
without these criteria function works well and gives for every task median based on "MP", however when I put in there my criteria I receive error:
error - Too few parameters. Expected 4 and then it says 'Object Variable or With block not set'
my input: DMedian("MP";"testForm2";"[TASK]= '" & [TASK] & "'")
*even when the Form is open it end up with the error.
*I probably need to find a different way to filter this query from the form, but I don't know how
Public Function DMedian(FieldName As String, _
TableName As String, _
Optional Criteria As Variant) As Variant
' Created by Roger J. Carlson
' http://www.rogersaccesslibrary.com
' Terms of use: You may use this function in any application, but
' it must include this notice.
'Returns the median of a given field in a given table.
'Returns -1 if no recordset is created
' You use this function much like the built-in Domain functions
' (DLookUp, DMax, and so on). That is, you must provide the
' 1) field name, 2) table name, and 3) a 'Where' Criteria.
' When used in an aggregate query, you MUST add each field
' in the GROUP BY clause into the into the Where Criteria
' of this function.
' See Help for more on Domain Aggregate functions.
On Error GoTo Err_Median
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL As String
Dim RowCount As Long
Dim LowMedian As Double, HighMedian As Double
'Open a recordset on the table.
Set db = CurrentDb
strSQL = "SELECT " & FieldName & " FROM " & TableName
If Not IsMissing(Criteria) Then
strSQL = strSQL & " WHERE " & Criteria & " ORDER BY " & FieldName
Else
strSQL = strSQL & " ORDER BY " & FieldName
End If
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
'Find the number of rows in the table.
rs.MoveLast
RowCount = rs.RecordCount
rs.MoveFirst
'Determine Even or Odd
If RowCount Mod 2 = 0 Then
'There is an even number of records. Determine the low and high
'values in the middle and average them.
rs.Move Int(RowCount / 2) - 1
LowMedian = rs(FieldName)
rs.Move 1
HighMedian = rs(FieldName)
'Return Median
DMedian = (LowMedian + HighMedian) / 2
Else
'There is an odd number of records. Return the value exactly in
'the middle.
rs.Move Int(RowCount / 2)
'Return Median
DMedian = rs(FieldName)
End If
Exit_Median:
'close recordset
rs.Close
Exit Function
Err_Median:
If Err.number = 3075 Then
DMedian = 0
Resume Exit_Median
ElseIf Err.number = 3021 Then
'EOF or BOF ie no recordset created
DMedian = -1
Resume Exit_Median
Else
MsgBox Err.Description
Resume Exit_Median
End If
End Function
The parameter separation character is comma and you are using a semi-colon
CHANGE:
DMedian("MP";"testForm2";"[TASK]= '" & [TASK] & "'")
TO:
DMedian("MP", "testForm2", "[TASK]= '" & [TASK] & "'")
Solution was to refer the text boxes in SQL declaration, Thank you guys
like this:
HAVING (((Data.[REV]< " & Me.crit1 & ") And (Data.[REV])>" & Me.crit2 & ") AND ((Reg.Age)<" & Me.Age1 & " And (Reg.Age)>" & Me.Age2 & " " & SQLcritComplete & "));"
NOT like this:
"HAVING (((Data.[REV]<[Form]![testForm2]![crit1]) And (Data.[REV])>[testForm2]![crit2]) AND ((Reg.Age)<[Form]![testForm2]![Age1] And (Reg.Age)>[Form]![testForm2]![Age2] & SQLcritComplete & "));"

MS Access - SQL Query for Max Date

I am creating a schedule calendar which has been working great, but I want to adjust the SQL so that it only shows when the next job has to be done. I was thinking the best way to achieve this would be via the MAX() function, however when i run the code Access doesn't seem to like it.
Public Sub LoadArray()
'This sub loads an array with the relevant variables from a query
Dim db As Database
Dim rs As Recordset
Dim rsFiltered As Recordset
Dim strQuery As String
Dim i As Integer
Dim Text23 As Integer
On Error GoTo ErrorHandler
Text23 = Forms.frmPreventativeMenu.Form.CompanyName.Value
strQuery = "SELECT tblWMYReports.Company, tblWMYReports.Machine, MAX(tblWMYReports.NextDate), tblWMYReports.WMY " _
& "FROM tblWMYReports " _
& "WHERE (((tblWMYReports.Company)= " & Text23 & " ));"
Set db = CurrentDb
Set rs = db.OpenRecordset(strQuery)
With rs
If Not rs.BOF And Not rs.EOF Then
'Ensures the recordset contains records
For i = 0 To UBound(MyArray)
'Will loop through the array and use dates to filter down the query
'It firsts checks that the second column has true for its visible property
If MyArray(i, 1) = True Then
.Filter = "[NextDate]=" & MyArray(i, 0)
'To filter you must open a secondary recordset and
'Use that as the basis for a query
'This makes sense as you are building a query on a query
Set rsFiltered = .OpenRecordset
If Not rsFiltered.BOF And Not rsFiltered.EOF Then
'If the recordset is not empty then you are able
'to extract the text from the values provided
Do While Not rsFiltered.EOF = True
MyArray(i, 2) = MyArray(i, 2) & vbNewLine & DLookup("MachineName", "tblMachine", "MachineID=" & rsFiltered!Machine)
MyArray(i, 2) = MyArray(i, 2) & " - " & DLookup("WMY", "tblWMY", "ID=" & rsFiltered!WMY)
rsFiltered.MoveNext
Loop
End If
End If
Next i
End If
.Close
End With
ExitSub:
Set db = Nothing
Set rs = Nothing
Exit Sub
ErrorHandler:
MsgBox "There has been an error. Please reload the form.", , "Error"
Resume ExitSub
End Sub
You are going to aggregate one column with an aggregate function like Sum(), Max(), Count() or similar, then every other column that isn't being aggregated must show up in the SQL's GROUP BY clause:
strQuery = "SELECT tblWMYReports.Company, tblWMYReports.Machine, MAX(tblWMYReports.NextDate), tblWMYReports.WMY " _
& "FROM tblWMYReports " _
& "WHERE (((tblWMYReports.Company)= " & Text23 & " )) " _
& "GROUP BY tblWMYReports.Company, tblWMYReports.Machine, tblWMYReports.WMY;"
I can't guarantee that is going to do what you want it to, since I'm not familiar with your data, code, or application, but it should get you through the error.
You must use a properly formatted string expression for the date value:
.Filter = "[NextDate] = #" & Format(MyArray(i, 0), "yyyy\/mm\/dd") & "#"

Insert values from one table to another, better performance - Access 2000, VBA?

I have made this method:
Public Sub Proba()
Dim CPANonEmptyColumns As Integer
CPANonEmptyColumns = 0
Dim Max As Integer
Max = 0
Dim Koloni As String
Koloni = ""
Dim strSQL As String
Dim intI As Integer
Dim rsCPA As DAO.Recordset
Dim rsCPANezbirni As DAO.Recordset
Dim dbs_t1t2 As DAO.Database
On Error GoTo ErrorHandler
Set dbs_t1t2 = CurrentDb
'Open a recordset on all records from the Employees table that have
'a Null value in the ReportsTo field.
strSQL = "SELECT * FROM CPA_t1t2"
Set rsCPA = dbs_t1t2.OpenRecordset(strSQL) '//, dbOpenDynaset)
'If the recordset is empty, exit.
If rsCPA.EOF Then Exit Sub
intI = 1
With rsCPA
Do Until .EOF
DoCmd.RunSQL "INSERT INTO CPA_nezbirni (tipprod, promet) VALUES ('" & ![tipprod] & "', '" & ![promet] & "');"
' check individual column if it has a value and increment max if CPANonEmptyColumns
If ![t4k1] <> Null Or ![t4k1] <> "" Then
CPANonEmptyColumns = CPANonEmptyColumns + 1
Koloni = Koloni & "t4k1,"
End If
If ![t4k2] <> Null Or ![t4k2] <> "" Then
CPANonEmptyColumns = CPANonEmptyColumns + 1
Koloni = Koloni & "t4k2,"
End If
If ![t4k3] <> Null Or ![t4k3] <> "" Then
CPANonEmptyColumns = CPANonEmptyColumns + 1
Koloni = Koloni & "t4k3,"
End If
If CPANonEmptyColumns > Max Then
Max = CPANonEmptyColumns
End If
Debug.Print "Red: " & Str(intI) & " Max: " & Str(Max) & ", Koloni: " & Koloni
.Edit
.MoveNext
CPANonEmptyColumns = 0
Koloni = ""
intI = intI + 1
Loop
End With
rsCPA.Close
dbs_t1t2.Close
Set rsCPA = Nothing
Set dbs_t1t2 = Nothing
ErrorHandler:
MsgBox "Error #: " & Err.Number & vbCrLf & vbCrLf & Err.Description
End Sub
Basically, I open two tables, CPA_t1t2 and CPA_nezbirni. I want to copy the appropriate values for the appropriate columns, tipprod and promet from CPA_t1t2 to CPA_nezbirni.
The problem is, the source table CPA_t1t2 has 18000 rows and it needs time to run all those "INSERT" queries with the statement:
DoCmd.RunSQL "INSERT INTO CPA_nezbirni (tipprod, promet) VALUES ('" & ![tipprod] & "', '" & ![promet] & "');"
I am always suspicions when it comes SQL about performance. Since it needed 3-4 minutes to finish the procedure and insert values into CPA_nezbirni, is the SQL more slower way to copy value from one table to another?
Is there better, faster way by using the procedure above and some VBA, trough the same "Do Until" loop?

VBA Query based on multiple "multiple select list boxes" in Access when not selecting an item from one of the multiple select boxes

I have the following vba that creates a query in a test Access database. I have two multiple select list boxes. The issue is, i want to be able to select multiple items from "Me![State]" and none from "Me![Animal]" and be able to run the query. However, this is not possible as the query language is not set up to handle that. It makes me select something from "Me![Animal]".
How do i revise the vba below to allow me to query on both multiple selection list boxes if one of the multiple list boxes does not have anything selected or if both have selections in them?
Private Sub Command6_Click()
Dim Q As QueryDef, DB As Database
Dim Criteria As String
Dim ctl As Control
Dim Itm As Variant
Dim ctl2 As Control
Dim ctl3 As Control
' Build a list of the selections.
Set ctl = Me![Animal]
For Each Itm In ctl.ItemsSelected
If Len(Criteria) = 0 Then
Criteria = Chr(34) & ctl.ItemData(Itm) & Chr(34)
Else
Criteria = Criteria & "," & Chr(34) & ctl.ItemData(Itm) _
& Chr(34)
End If
Next Itm
If Len(Criteria) = 0 Then
Itm = MsgBox("You must select one or more items in the" & _
" list box!", 0, "No Selection Made")
Exit Sub
End If
Set ctl2 = Me![State]
For Each Itm In ctl2.ItemsSelected
If Len(Criteria2) = 0 Then
Criteria2 = Chr(34) & ctl2.ItemData(Itm) & Chr(34)
Else
Criteria2 = Criteria2 & "," & Chr(34) & ctl2.ItemData(Itm) _
& Chr(34)
End If
Next Itm
If Len(Criteria2) = 0 Then
Itm = MsgBox("You must select one or more items in the" & _
" list box!", 0, "No Selection Made")
Exit Sub
End If
' Modify the Query.
Set DB = CurrentDb()
Set Q = DB.QueryDefs("animalquery")
' Modify the Query.
Set DB = CurrentDb()
Set Q = DB.QueryDefs("animalquery")
Q.SQL = "Select * From [table1] Where [table1].[type] In (" & "'Animal'" & _
")" & " and [table1].[animal] in (" & Criteria & _
")" & " and [table1].[state] in (" & Criteria2 & _
")" & ";"
Q.Close
' Run the query.
DoCmd.OpenQuery "animalquery"
End Sub
EDIT - Fix comparison as per comment
You can do this with a simple check of your Criteria vaiables.
You already do the the length check - just use it later on when you build the dynamic SQL.
I added a strSQL variable to make it easier to track what's happening. And adjusted the error message to allow one or other criteria being empty
Private Sub Command6_Click()
Dim Q As QueryDef
Dim DB As Database
Dim Criteria As String
Dim ctl As Control
Dim Itm As Variant
Dim ctl2 As Control
Dim ctl3 As Control
' Use for dynamic SQL statement'
Dim strSQL As String
Set ctl = Me![Animal]
For Each Itm In ctl.ItemsSelected
If Len(Criteria) = 0 Then
Criteria = Chr(34) & ctl.ItemData(Itm) & Chr(34)
Else
Criteria = Criteria & "," & Chr(34) & ctl.ItemData(Itm) & Chr(34)
End If
Next Itm
Set ctl2 = Me![State]
For Each Itm In ctl2.ItemsSelected
If Len(Criteria2) = 0 Then
Criteria2 = Chr(34) & ctl2.ItemData(Itm) & Chr(34)
Else
Criteria2 = Criteria2 & "," & Chr(34) & ctl2.ItemData(Itm) & Chr(34)
End If
Next Itm
If (Len(Criteria) = 0) And (Len(Criteria2) = 0) Then
Itm = MsgBox("You must select one or more items from one of the list boxes!", 0, "No Selection Made")
Exit Sub
End If
' Modify the Query.
Set DB = CurrentDb()
Set Q = DB.QueryDefs("animalquery")
' Modify the Query.
Set DB = CurrentDb()
Set Q = DB.QueryDefs("animalquery")
strSQL = "Select * From [table1] Where [table1].[type] In (" & "'Animal')"
If (Len(Criteria) <> 0) Then ' Append Animal Criteria
strSQL = strSQL & " AND [table1].[animal] IN (" & Criteria & ")"
End If
If (Len(Criteria2) <> 0) Then ' Append State Criteria
strSQL = strSQL & " AND [table1].[state] IN (" & Criteria2 & ")"
End If
Q.SQL = strSQL
Q.Close
' Run the query.
DoCmd.OpenQuery "animalquery"
End Sub