How to write a value into access database faster - VBA (excel) - vba

I am trying to store the values inside an access database from excel using vba.
I have a form in Excel where I get the Inputs from the User.
On VBA, In the Locals window, I could see the values assigned to the object as below,
Name = Mike
Age = 23
Occupation = Student
On the Access database, I have a table called as UserTable which has columns called as ID, Name, Age, Occupation and now how do I pass the values from VBA to Access database.
I would want to add the value record by record and faster at the same time.
Here is where I am getting the error
strSQL = "PARAMETERS [Name] TEXT(255), [Age] INTEGER, [Occupation] TEXT(255);" _
& " INSERT INTO UserTable([User Name], [User Age], [User Occupation]);"
Please help me with this on my learning.

Create a reference to the ADO recordset library
create and open a Connection object to the access database
Dim Conn as new adodb.connection
conn.connectionstring = "google for connection string here"
conn.open
create a string holding an append query (watch out: you need commas between fields and ' around strings)
Dim strSQL as string
StrSql = "INSERT INTO [Usertable] ( Name, Age, Occupation ) "
strsql = strsql & "Values('" & me.Name & "'," & me.age & ",'" & me.occupation & "')"
Use EXECUTE to run this string
conn.execute strsql

Related

it gives an error when i run a SQL script

I'm trying to INSERT INTO with SQL in a table in VBA but it gives a error while running this script. why?
I was expecting it to add the values to the table but it gives an error instead, does anyone has the solution for this?
DoCmd.RunSQL "INSERT INTO tblScores (Student, Score, Date, ExamType, Lesson) VALUES (cbStudent.Value,txtScore.Value,txtDate.Value,cbExamType.value,cbLesson.Value);"
The error message:
The form values need to be concatenated to the SQL string, not being enclosed to it.
For example:
"WHERE ID =" & IdControl.Value
But this way is not recommended for various reasons. Best to create a temporary query and pass the values as parameters. If you need to run it frequently, create a permanent query and just call it - it will be slightly faster.
Const SQL As String = "PARAMETERS [Student] Text (255), [Score] IEEESingle, [Date] DateTime, [ExamType] Text (255), [Lesson] Text (255); " & _
"INSERT INTO tblScores (Student, Score, [Date], ExamType, Lesson) " & _
"SELECT [Student] AS [Student], [Score] AS [Score], [Date] AS [Date], [ExamType] AS [ExamType], [Lesson] AS [Lesson];"
Dim q As DAO.QueryDef
Set q = CurrentDb().CreateQueryDef("", SQL) 'temporary query
q.Parameters("[Student]").Value = cbStudent.Value
q.Parameters("[Score]").Value = txtScore.Value
q.Parameters("[Date]").Value = txtDate.Value
q.Parameters("[ExamType]").Value = cbExamType.Value
q.Parameters("[Lesson]").Value = cbLesson.Value
q.Execute
q.Close
Keep in mind I don't know the actual data-types of your table fields, so some of the params could be off - the score for example.
Try this:
Dim varStudent as String
.
varStudent = cbStudent
.
In SQL String: VALUES ( '" & varStudent & "', '" & varTxtScore & "'
'" = SingleQuote DoubleQuote

Syntax Error in INSERT INTO Statement (Error 3134)

I'm using MS Access 2013. My current issue is with the following code, I use to log user activity.
Table is called: tbl-activitylog and has five columns :
id
timestamps
Username
Activity
Additional
I checked code many times char after char and don't know what's wrong :(
TempVars("UserName").Value = "admin"
Logging("Logon", "system")
Public Sub Logging(Activity, Additional As String)
Dim sql_code As String
sql_code = "INSERT INTO tbl-activitylog(Username, Activity, Additional) VALUES('" & TempVars("UserName").Value & "','" & Activity & "','" & Additional & "')"
Debug.Print sql_code
CurrentDb.Execute sql_code
End Sub
Debug print shows:
INSERT INTO tbl-activitylog(Username, Activity, Additional) VALUES('admin','Logon','System')
Becaus of using "-" you have to do it in this way [tbl-activitylog]
sql_code = "INSERT INTO [tbl-activitylog](Username, Activity, Additional) VALUES('" & TempVars("UserName").Value & "','" & Activity & "','" & Additional & "')"
This 3134 error denotes a syntax error in your INSERT statement. As the name of your table contains a dash, you need to enclose it between brackets :
INSERT INTO [tbl-activitylog]
(Username, Activity, Additional)
VALUES('admin','Logon','System')
Generally speaking you may as well enclose all fields and table names, to avoid all risks of clashes with ms-access reserved words, like :
INSERT INTO [tbl-activitylog]
([Username], [Activity], [Additional])
VALUES('admin','Logon','System')
Consider a parameterized query, an industry best practice in any application layer language running SQL in any database. With QueryDefs, you can parameterize queries in MS Access.
Even more MS Access will not allow you to save queries with syntax issues. So, be sure to escape special characters and reserved words with square brackets or backticks.
SQL (save below as a query object)
PARAMETERS UsernameParam Text, ActivityParam Text, AdditionalParam Text;
INSERT INTO [tbl-activitylog] ([Username], [Activity], [Additional])
VALUES ([UsernameParam], [ActivityParam], [AdditionalParam])
VBA (reference above query and bind values without quotes or concatenation)
TempVars("UserName").Value = "admin"
Logging("Logon", "system")
Public Sub Logging(Activity, Additional As String)
Dim sql_code As String
Dim qdef As QueryDef
Set qdef = CurrentDb.QueryDefs("mySavedQuery")
' BIND PARAMS
qdef![UsernameParam] = TempVars("UserName")
qdef![ActivityParam] = Activity
qdef![AdditionalParam] = Additional
qdef.Execute dbFailOnError
Set qdef = Nothing
End Sub

Avoiding SQL Injection in MS Access [duplicate]

This question already has answers here:
How do I use parameters in VBA in the different contexts in Microsoft Access?
(2 answers)
Closed 4 years ago.
I'm trying to better understand parameterized sql as a solution to SQL injection.
Lets say I have a tblCustomer with the fields CustName, Phone and Address. Lets also say I have an input form for new customers to enter their data, with controls called txtName, txtPhone and txtAddress.
I could run the following vba code:
dim strName, strPhone strAddress, strSQL as string
strName = me.txtName
strPhone = me.txtPhone
strAddress = me.txtAddress
strSQL = "INSERT INTO tblCustomer (CustName, Phone, Address) _
VALUES (" & strName & ", " & strPhone & ", " & strAddress & ");"
DoCmd.RunSQL strSQL
But then if someone nominated the address "Robert'); DROP TABLE tblCustomer; --" (wink) I'd have some serious problems.
I've used vba parameters, but they aren't helping me. So when people say use parameters to fix the issue, what do they mean?
Using a prepared statement with positional parameters eliminates the chance that someone may SQL inject you:
strSQL = "INSERT INTO tblCustomer (CustName, Phone, Address) " &
"VALUES ([str_name], [str_phone], [str_address]);"
Set qdf = db.CreateQueryDef(vbNullString, strSql)
With qdf
.Parameters("str_name").Value = strName
.Parameters("str_phone").Value = strPhone
.Parameters("str_address").Value = strAddress
.Execute dbFailOnError
End With
See here:
https://msdn.microsoft.com/en-us/library/office/ff845220.aspx
A longer winded explanation is that a parameterized query allows you to use a variable within your SQL query, and that variable will be properly escaped if it's a string or matched to your data type (for type checking), and prevent the problem that you've listed.

Getting user ID from a Spreadsheet and Access database

Why is this code not working? Sorry for the generic question....
I am tasked with generating reports with reference information that needs to be drawn from an access database and an excel spreadsheet.
Basically in my role I'm responsible for providing service to people who live in a community; the record of all the people I provide service for is contained in an access database. There's reference information; address, name, situation, and other information needed for regular reports to funders or the board of directors.
I also provide service to local businesses; this information is contained within a spreadsheet, and not a database. The information could be put into a relational database, with the two related together; but there is resistance at the organization for significant changes to the system, nor is there really the knowledge of how to do this.
So I'm trying to move forward with a spreadsheet - if I provide service to person A or organization B, that this spreadsheet will check both the access database, and the excel spreadsheet to see whether that person or organization is entered; if it is, it should populate a table with that information, and assign it a unique code.
The unique code is determined on the basis of the database; whether or not the person or organization has been entered into the database before.
The spreadsheet I am working at the base with is this:
The bottom table I am looking to be a 'lookup' table. Its name is Lookup. The code I want to run with it looks like this (but obv not is this):
Sub getUserID()
Dim myTable As ListObject
Set myTable = Sheets("Client Codes").ListObjects("Lookup")
If myTable.ListRows.Count >= 1 Then
myTable.DataBodyRange.Delete
End If
With Sheets("Client Codes").ListObjects("Lookup").Add(SourceType:=0, Source:=Array(Array("ODBC;DSN=MS Access Database;DBQ=C:\database\here\test.accdb;DefaultDir=F:\Housing;DriverId=25;FIL=MS Access;MaxBufferSize=2048;PageTimeo"), Array("ut=5;")), Destination:=myTable.Range(Cells(1, 1)))
.CommandText = Array("SELECT Clients.ID, Clients.LastName, Clients.FirstName " & Chr(13) & "" & Chr(10) & "FROM `C:\database\here\test.accdb`.Clients Clients" & Chr(13) & "" & Chr(10) & "WHERE (Clients.LastName='" & Range("b1").End(xlDown) & "') AND (Clients.FirstName='" & Range("c1").End(xlDown) & "')")
End With
With Sheets("Client Codes").ListObjects("Lookup").Add(SourceType:=0, Source:=Array(Array("ODBC;DSN=Excel Files;DBQ=C:\spreadsheet\here\text.xlsx;DefaultDir=c:\spreadsheet;DriverId=1046;MaxBufferSize=2"), Array("048;PageTimeout=5;")), Destination:=myTable.Range(Cells(1, 1)))
.CommandText = Array("SELECT `Businesses$`.Operation" & Chr(13) & "" & Chr(10) & "FROM `C:\spreadsheet\here\test.xlsx`.`Businesses$` `Businesses$`" & Chr(13) & "" & Chr(10) & "WHERE (`Businesses$`.Operation='" & Range("b1").End(xlDown) & "')")
End With
End Sub
The hope is to be able to query the database on the basis of either a persons first and last name, or to query the spreadsheet on the basis of organization name; and if there is a value that is found, to add some information to the table 'Lookup'. If nothing is found, then I will know its a new entry, and enter in the information as such.
For reference, the database has 3 fields (ID, LastName, FirstName); and the spreadsheet has 1 column (Operation).
Really the confusion is focused here:
How to 'add' the information based on a query to the listobject to a pre-existing table
How to do this both with an access database and an Excel spreadsheet
Any suggestions on other ways how this can be done would be appreciated; pull information from multiple data sources into one table so that it can be validated in that table.
EDIT: If I did this through Access or another database program, I would do an INNERJOIN on two tables; one of people, the other of businesses. I'm looking to keep excel though - I find it to be more user friendly.
EDIT: Code based on Ian's response....generates the following error message:
'run time error -2147467259, could not find installable ISAM'
Research on the internet seems to indicate the following:
1) People have gotten this error before
2) There might not be a proper DLL installed - not certain this is the case, because I'm trying to access access from excel, and it doesn't seem like there is a DLL for access here: https://support.microsoft.com/en-us/kb/209805
3) There might be issue of how the connection string is framed. The data source might need to be in quotes, the JET OLEDB needs to be used not ACE, the connection string needs to be extended to include 'extended properties' here: Error: "Could Not Find Installable ISAM"
The last one is obviously the biggest target (and has the most error about it).
Option Explicit
Sub getUserID()
Dim cmd As New ADODB.Command
Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strConn As String
Dim strSQL As String
Dim firstName As String
Dim lastName As String
firstName = "John"
lastName = "Smith"
strConn = "Provider = Microsoft.ACE.OLEDB.12.0;'DataSource=F:\Housing\bpTest.accdb'"
conn.Open strConn
strSQL = "SELECT * FROM Table Where FirstName = '" & firstName & "' AND LastName = '" & lastName & "';"
'& ... ' or You could put your InnerJoin SQL here
rs.Open strSQL, conn, adOpenDynamic, adLockOptimistic
If rs.EOF Then 'If the returned RecordSet is empty
MsgBox ("No record found")
Else
MsgBox (rs.Index)
End If
end sub
You will most like want to use ActiveX Data Objects to accomplish this. This will let you to pull data from the access database and also update the records in the access database from Excel.
Here is the Microsoft reference material: https://msdn.microsoft.com/en-us/library/ms677497(v=vs.85).aspx
And some sample code:
Dim cmd As New adodb.Command
Dim conn As New adodb.Connection
Dim rs As New adodb.Recordset
Dim strConn As String
strConn = "Provider = Microsoft.ACE.OLEDB.12.0;" _
& "Data Source=C:\AccessDatabse.accdb"
conn.Open strConn
strSQL = "SELECT * FROM Table Where FristName =" & strName & ... ' or You could put your InnerJoin SQL here
rs.Open strSQL, conn, adOpenDynamic, adLockOptimistic
If rs.EOF then 'If the returned RecordSet is empty
'...there is no match in database
Else
'the rs object will hold the ID you are looking for
End If
you can add a new records to the Access Database with:
myFieldList = Array("ID", "FirstName", "LastName")
myValues = Array(IDValue, FirstNameValue, LastNameValue)
rs.AddNew myFieldList, myValues

Access VBA type mismatch

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