Access VBA type mismatch - sql

I'm creating a database for a local rental company. What I'm trying to do right now is create some code that can be periodically run to add bills to the database.
I have two tables I'm referencing here, the first is tblRental which is a table of rental units which includes rentalID's as a primary key, rental status, and the monthly rent, which is different on each unit. The other is tblTransaction which among other things includes the rentalID as a foreign key in a 1 to many relationship, and the amount for each bill which is named UnitRate. In the database rentalID and UnitRate are both set to numbers.
My code right now is
Dim maxRentalID As Integer
Dim db As Database
Dim rentID As DAO.Recordset
Dim unit As DAO.Recordset
Set db = CurrentDb
maxRentalID = Combo4.Value
For i = 1 To maxRentalID
Set rentID = db.OpenRecordset("SELECT tblRental.RentalID, tblRental.Status FROM tblRental WHERE (((tblRental.Status)='3') AND ((tblRental.RentalID)=" & i & "));")
Set unit = db.OpenRecordset("SELECT tblRental.Rentalcharge FROM tblRental WHERE (((tblRental.RentalID)=" & i & "));")
If rentID Is Not Null Then
DoCmd.RunSQL "INSERT INTO tblTransction ([RentalID], [UnitRate]) VALUES (" & rentID, unit & ");"
End If
Next
maxRentalID is obtained from a form which determines the ID of the last record so that the for loop will go through until the end.
Right now I get a type mismatch error and it tells me the problem is with rentID in the DoCmd.RunSQL line.
I'm trying to make the loop run a query, and if it's a valid result (status=3 on a RentalID that exists), insert a new record into tblTransaction with that RentalID and corresponding billing rate.
Based on what the debugger says I assume that what's happening is the SQL isn't being evaluated into a statement with the query value being assigned to the variable and it's trying to put the statement into a number field which doesn't work. I'm not sure how to make it evaluate properly however. I've tried using OpenRecordSet for that but it doesn't work.

I would do it without loop and opening recordsets:
Dim maxRentalID As Integer
maxRentalID = Combo4.Value
CurrentDb.Execute "INSERT INTO [tblTransction] ([RentalID], [UnitRate]) " & _
"SELECT [tblRental].[RentalID], [tblRental].[Rentalcharge] " & _
"FROM [tblRental] " & _
"WHERE [tblRental].[Status]='3' AND " & _
"[tblRental].[RentalID] BETWEEN 1 AND " & maxRentalID

Related

Problem importing an excel workbook into Access and adding a column; error 3127

I am creating a form in an Access database that allows a user to import an Excel workbook into the database, then inserts a column with that day's date as a way to log when the record was imported, with the idea that I can later compare this to a master database and update accordingly.
My code is below:
Private Sub btnImport_Click()
'create a new file system object that will check for conditions and import the file as a new table if a valid name is chosen
Dim FSO As New FileSystemObject
Dim strSQL As String
'Dim curDatabase As Object
Dim tableTest As Object
Dim fieldNew As Object
Dim todayDate As Date
Dim tempTable As String
tempTable = "TempTable" & CStr(Date)
'MsgBox TempTable
'If no file name in box
If Nz(Me.txtFileName, "") = "" Then
MsgBox "Please choose a file."
Exit Sub
End If
'If a file name is in box and the file can be located
If FSO.FileExists(Me.txtFileName) Then
fileImport.ImportExcel Me.txtFileName, tempTable
'once it imports the table, it then adds today's date (the upload date)
todayDate = Date
strSQL = "INSERT INTO tempTable (Upload_Date) Values (#" & Date & "#);"
DoCmd.RunSQL strSQL
'DoCmd.RunSQL ("DROP Table TempTable")
Else
'Error message if file can't be found
MsgBox "File not found."
End If
End Sub
Unfortunately, right now I am getting two problems.
The first is
run-time error 3127: The INSERT INTO statement contains an unknown
field name.
I thought I wanted to insert a new field, so I'm a little perplexed by this error.
I'm also getting another error; the compiler doesn't seem to like when I use tempTable for the table name. I'm trying to use a reference to the table name, rather than the actual name of the table itself, because this will end up being a daily upload, so the name of the table that is having this column inserted into it will change every day.
I appreciate any guidance that you can give; I'm fairly new to VBA.
UPDATE: I ended up solving this issue by A. using an UPDATE statement and using CurrentDb.Execute to add the date. I found that this worked for me:
strSQL = "ALTER TABLE TempTable ADD COLUMN Upload_Date DATE;"
strSQL2 = "UPDATE TempTable SET Upload_Date = '" & Date & "'"
DoCmd.RunSQL strSQL
CurrentDb.Execute strSQL2
INSERT INTO doesn't add columns, it just adds rows (with data in existing columns). Look into ALTER TABLE ( https://learn.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/alter-table-statement-microsoft-access-sql )
I'm not sure if it's related, but the table name you use in strSQL is "tempTable", yet the table name you pass to fileImport.ImportExcel is "TempTable" (i.e. the capitalization of the first letter is inconsistent).
If the variable "tempTable" is meant to hold the name of the table (so it can be used for different table names) then it should be outside of the SQL strings:
strSQL= "ALTER TABLE " & tempTable " & " ADD COLUMN Upload_Date DATE;"
strSQL2 = "UPDATE " & tempTable & " SET Upload_Date = '" & Date & "';"
Otherwise you are amending and updating a table called "TempTable" rather than inserting the calculated table name from the variable into the SQL string.
Also note that there should be a semi-colon at the end of strSQL2 as well.

how to update a table with a random record from another table

I'm trying to retrieve a random record from a Query(trackList) and update a table (setList) with that record using VBA in MS Access. I've assigned integer values from my recordset and when I run the debug everything runs correctly. when I call this up from a batch file it continues to retrieve the records in alphanumeric order. Is there a better way to achieve this?
Set dbs = CurrentDb
Set rst = dbs.OpenRecordset("_Sun00Q")
strName = rst.Fields("PLNames")
strSetName = rst.Fields("SetName")
Set rst2 = dbs.OpenRecordset(strName & "_trackList_RndOrd")
intPLNid = rst2.Fields("PLNid")
intId = rst2.Fields("id")
SQL = "UPDATE " & strSetName & " SET id=" & intId & " WHERE PLNid=" & intPLNid
DoCmd.RunSQL SQL
You could open your first table as a recordset, generate a random integer, then move the AbsolutePosition of the recordset to that random integer. That should get you to a random spot in the recordset. Then add that record to your second table.

Error 3346, trying to INSERT INTO, two consecutive tables

I have those two tables is MS Access :
lkpSchemaPIT :
| UID | lkpSchemaTitleEng |
|-----|--------------------------|
|--1--|---------Title1-----------|
|--2--|---------Title2-----------|
...
lkpSchemaPITChronology :
| ID | UID | PUID | Sort | Level | DateStart | DateEnd |
|----|-----|------|------|-------|-----------|---------|
|--0-|--1--|--0---|---5--|--2----|---Now()---|--NULL---|
...
The first table contains just nodes that i'm going to put in a treeview in access. I use the second table to construct the tree, but also keep track of all the parent that a node could've had through the years. You can see that the UID in the two tables are the same, but they have not a relationship between them, when I build the tree, I use a query with a join on it.
My problem is : When I want to add a new node in the lkpSchemaPIT table, I need to be able to add its "treeview" info as well (Parent, Sort, Level, etc.).
This is my code so far :
With CurrentDb
.Execute _
"INSERT INTO lkpSchemaPIT " & _
"(lkpSchemaTitleEng) " & _
"VALUES " & _
"('" & Title & "')"
.Execute _
"INSERT INTO lkpSchemaPITChronology VALUES (" & .OpenRecordset("SELECT ##IDENTITY").Fields(0) & ", " & [ParentID] & ", " & [NewSort] & ", " & [Level] & ", " & Date & ", null)"
End With
ParentID, NewSort, Level are 3 variables that have been determined before I call all this.
The "Date" parameters is the VBA function that returns the current date.
I know that the first INSERT INTO is working because a new value is displayed in my table. But the second INSERT INTO isn't working and I was able to get the error :
Error 3346 - Number of query values and destination fields are not the same.
Is anyone ever had this kind of problem ?
Once again, here is an example where parameterized queries would be invaluable as you avoid quote enclosures (including # for date/times) and string concatenation that conflates data and SQL together, rendering hard to read and maintain code.
MS Access allows the PARAMETERS clause where you can define the parameter placeholder names and data types and then in VBA you can bind values to such parameters using QueryDefs. No quotes needed or string interpolation.
SQL (save both as stored queries)
PARAMETERS TitleParam Text(255);
INSERT INTO lkpSchemaPIT (lkpSchemaTitleEng)
VALUES (TitleParam);
PARAMETERS UIDParam Long, PUIDParam Long, SortParam Long,
LevelParam Long, DateStart Datetime;
INSERT INTO lkpSchemaPITChronology (UID, PUID, [Sort], [Level], DateStart)
VALUES (UIDParam, PUIDParam, SortParam, LevelParam, DateStartParam);
VBA
...
Dim qdef As QueryDef
With CurrentDb
' FIRST QUERY
Set qdef = .QueryDefs("myFirstSavedAppendQuery")
qdef!TitleParam = [Title]
qdef.Execute dbFailOnError
' SECOND QUERY
Set qdef = .QueryDefs("mySecondSavedAppendQuery")
qdef!UIDParam = .OpenRecordset("SELECT ##IDENTITY").Fields(0)
qdef!PUIDParam = [ParentID]
qdef!SortParam = [NewSort]
qdef!LevelParam = [Level]
qdef!DateStart = Date()
qdef.Execute dbFailOnError
End With
Set qdef = Nothing

How to run parameterized query from VBA. Parameters sourced from recordset

I have a form where a user selects a vendor's name from a combobox, whose catalog file is to be imported. The combobox selection then drives a query to create a one-record recordset (rsProfile) containing several profile variables queried from a table of all vendor profiles. These variables are then used in a series of different queries to reformat, translate and normalize the vendor's uniquely structured files to a standardized format that can be imported into our system.
I am frustrated that I can't figure out how to build my stored queries that will use one or more parameters that are automatically populated from the profile recordset.
Here is my rsProfile harvesting code. It works. Note that intVdrProfileID is a global variable set and used in other places.
Private Sub btn_Process_Click()
Dim ws As Workspace
Dim db, dbBkp As DAO.Database
Dim qdf As DAO.QueryDef
Dim rsProfile, rsSubscrip As Recordset
Dim strSQL As String
Dim strBkpDBName As String
Dim strBkpDBFullName As String
strBkpDBName = Left(strVdrImportFileName, InStr(strVdrImportFileName, ".") - 1) & "BkpDB.mdb"
strBkpDBFullName = strBkpFilePath & "\" & strBkpDBName
Set db = CurrentDb
Set ws = DBEngine.Workspaces(0)
MsgBox ("Vendor Profile ID = " & intVdrProfileID & vbCrLf & vbCrLf & "Backup file path: " & strBkpFilePath)
' Harvest Vendor Profile fields used in this sub
strSQL = "SELECT VendorID, Div, VPNPrefix, ImportTemplate, " & _
"VenSrcID, VenClaID, ProTyp, ProSeq, ProOrdPkg, ProOrdPkgTyp, JdeSRP4Code, " & _
"PriceMeth, " & _
"ProCost1Frml, ProCost2Frml, " & _
"ProAmt1Frml, ProAmt2Frml, ProAmt3Frml, ProAmt4Frml, ProAmt5Frml " & _
"FROM tZ100_VendorProfiles " & _
"WHERE VendorID = " & intVdrProfileID & ";"
Set qdf = db.QueryDefs("qZ140_GetProfileProcessParms")
qdf.SQL = strSQL
Set rsProfile = qdf.OpenRecordset(dbOpenSnapshot)
DoCmd.OpenQuery "qZ140_GetProfileProcessParms"
' MsgBox (qdf.SQL)
I have used QueryDefs to rewrite stored queries at runtime, and although it works, it is quite cumbersome and does not work for everything.
I was hoping for something like the sample below as a stored query using DLookups. I can get this to work in VBA, but I can't get anything to work with stored queries. I am open to other suggestions.
Stored Query "qP0060c_DirectImportTape":
SELECT
DLookUp("[VPNPrefix]","rsProfile","[VendorID]=" & intVdrProfileID) & [PartNo] AS VenPrtId,
Description AS Des,
DLookup("[Jobber]","rsProfile",[VendorID=" & intVdrProfileID) AS Amt1,
INTO tP006_DirectImportTape
FROM tJ000_VendorFileIn;
ADDENDUM:
Let me adjust the problem to make it a bit more complex. I have a collection of about 40 queries each of which use a different collection of parameters (or none). I also have a table containing the particular set of queries that each vendor 'subscribes' to. The goal is to have a database where a non-coding user can add new vendor profiles and create/modify the particular set of queries which would be run against that vendor file. I have almost 100 vendors so far, so coding every vendor seperately is not practical. Each vendor file will be subjected to an average of 14 different update queries.
Simplified Example:
Vendor1 file needs to be processed with queries 1, 2 and 5. Vendor2 file might need only update queries 2 and 4. The parameters for these queries might be as follows:
query1 (parm1)
query2 (parm1, parm4, parm8, parm11)
query4 (parm5, parm6, parm7, parm8, parm9, parm10, parm11)
query5 () -no parms required
This is the core query processing that loops through only the queries relevant to the current vendor file. rsSubscrip is the recordset (queried from a master table) containing this filtered list of queries.
' Run all subscribed queries
MsgBox "Ready to process query subscription list."
With rsSubscrip
Do While Not .EOF
db.Execute !QueryName, dbFailOnError
.MoveNext
Loop
.Close
End With
You can set the parameters of a predefined query using the syntax;
Set qdf = CurrentDB.QueryDefs(QueryName)
qdf.Parameters(ParameterName) = MyValue
To add parameters to the query, add the following before the SELECT statement in the sql
PARAMETERS [ParameterOne] DataType, [ParameterTwo] DataType;
SELECT * FROM tblTest;

Comparing a virtual child's filters to parent table

I haven't a clue as to how to do this. I'm using Access 2007, and coding in VBA and SQL.
Table A has Data, accounts and amounts. Users can use form B to access subsets of the data in A, say, all the rows with amounts between $50 and $100.
When the user is looking at a row, I need to know if there are any other rows with the same account that are excluded from their view. In other words, I need to know if there are rows visible in the parent that aren't visible in the child.
I think a solution is to determine what filters are active on their view, and then I can use dcount to compare. I don't know how to get at the filters that are active in their view, though. And there may be an easier way - I am out of my depth here.
Let us assume that TableA has a primary key ID. Using the current event for the FormB:
Dim rs AS DAO.Recordset
dAmt = Me.Amount
sAcc = Me.Account
''Get a list of visible IDs
With Me.RecordsetClone
.MoveFirst
Do While Not .EOF
If !Amount=dAmt And !Account=sAcc Then
sIDs = sIDs & "," & .ID
End If
.MoveNext
Loop
End with
''Other IDs
sSQL = "SELECT * FROM TableA "
& "WHERE Amount = " & dAmt _
& "Account = '" & sAcc _
& "' ID Not In (" & Mid(sIDs,2) & ")"
CurrentDB.CreateQueryDef("NewQ",sSQL")
Docmd.OpenQuery NewQ
The above is untested, and as it stands, will only run once, if it runs at all, because a new query is created, rather than an existing query being edited.