Inserting data into MySQL database with VBA - mysql

I have a simple macro to insert data from Excel into a MySQL database:
Dim conn As ADODB.Connection
Dim sqlstr As String
Dim rs As ADODB.Recordset
Dim Crow As Long, Lrow As Long
Dim Item As String, Price As Long, weight As Long, category As String
Set conn = New ADODB.Connection
conn.Open "DRIVER={MySQL ODBC 5.1 Driver};" & _
"SERVER=localhost;" & _
"PORT=3306" & _
"DATABASE=spendings;" & _
"USER=root;" & _
"PASSWORD=root;" & _
"Option=3"
Set rs = New ADODB.Recordset
Lrow = Cells(Rows.Count, 1).End(xlUp).Row
For Crow = Lrow To 2 Step -1
Item = Sheets("Sheet1").Range("A" & Crow).Value
Price = Sheets("Sheet1").Range("B" & Crow).Value
weight = Sheets("Sheet1").Range("C" & Crow).Value
category = Sheets("Sheet1").Range("D" & Crow).Value
sqlstr = "INSERT INTO items VALUES('" & Item & "','" & Price & "','" & weight _
& "', (SELECT idCategory FROM category WHERE Name='" & category & "'))"
rs.Open sqlstr, conn, adOpenStatic
Next
I am getting an error on the following line:
rs.Open sqlstr, conn, adOpenStatic
and no idea how to proceed.

As others have suggested, there is definitely a problem with your SQL string. Check out the syntax for the INSERT INTO SELECT statement here. Its often useful to test and debug your SQL strings in a database design tool such as MySQL Workbench before putting them into your code. You could also debug.print(sqlstr) to see what your string is returning e.g:
sqlstr = "INSERT INTO items ('" & Item & "','" & Price & "','" & weight _
& "', (SELECT idCategory FROM category WHERE Name='" & category & "'))"
debug.print(sqlstr)
rs.Open sqlstr, conn, adOpenStatic
I don't know your database structure but I can see some syntax errors in your string. You don't need VALUES before your columns (see above documentation). Also, you're trying insert data into 3 columns:
INSERT INTO items VALUES('" & Item & "','" & Price & "','" & weight _ & "')
but your SELECT query is only returning 1 column:
SELECT idCategory FROM category WHERE Name='" & category & "'.
Posting the debug.print output might help with further debugging.

Query was wrong. Thank you. Fixed it to
sqlstr = "INSERT INTO items (Name, Price, weight, store_Id, category_Id) VALUES('" & Item & "','" & Price & "','" & weight_
& "', (SELECT idCategory FROM category WHERE Name='" & category & "'),'" & store & "');"
Copied into workbench and it works:
mysql
But I am still getting the same error: run time error -2147217887(80040e21)

Related

Getting the newly added AutoID of MySQL using VBA in MS Access

I have a MS Access app with a MySQL database. I have tried numerous ways from Stack Overflow but can't get the primary key of a newly added row.
I have tried everything I can find with no luck.
Set pxRST = db.OpenRecordset("SELECT * from tblPatients WHERE dispenseID = " & oPxID & " AND ChemistID = " & chemID, dbOpenDynaset, dbSeeChanges)
if pxrst.eof then
pxRST.AddNew
pxRST("dispenseid") = oPxID
pxRST("chemistID") = chemID
pxRST("firstname") = firstName
pxRST("lastname") = lastName
pxRST("address") = Address
pxRST("postcode") = postcode
pxRST("phonenumber") = phonenumber
pxRST.Update
pxRST.Bookmark = pxRST.LastModified
gPxID = pxRST!PatientID
Debug.Print gPxID
end if
This gave a "record is deleted" error
I have also tried using one that had
gPxID = currentdb.openrecordset("SELECT ##identity").value(0)
This just game me 0 as a figure
I did go into MYSQL workbench and try
INSERT INTO tblpatients
SELECT ##IDENTITY
and I did get a new record's ID.
So I've tried hard and got so far but I just can't figure it out from here and how to get this working in VBA.
I'm currently working on using QueryDefs, but I'm very new to this and haven't really got there I don't think.
Dim qdf2 As DAO.QueryDef
strSQL = "INSERT INTO tblPatients (dispenseid,chemistID,firstname,lastname,address,postcode,phonenumber) " & _
"VALUES (" & oPxID & "," & chemID & ",'" & firstName & "','" & lastName & "','" & Address & "','" & postcode & "','" & phonenumber & "' )"
Set qdf2 = db.QueryDefs("quGetPxDetails")
With qdf2
.SQL = strSQL
.Connect = oCon
qdf2.Execute
End With
It rather depend upon whether your tblPatients has an auto increment primary key or not.
If it does then you should not be assigning it a value manually, ie your
INSERT INTO tblPatients (dispenseid,chemistID,firstname,lastname,address,postcode,phonenumber) " & _
"VALUES (" & oPxID & "," & chemID & ",'" & firstName & "','" & lastName & "','" & Address & "','" & postcode & "','" & phonenumber & "' )"
is not inserting anything into the PK.
Lets assume that you do have a column in tblPatients called
PatientID of type int(11) NOT NULL AUTO_INCREMENT,
Now, after you insert a new record you can get back the id of that inserted record using the function
LAST_INSERT_ID()
so
Select LAST_INSERT_ID() as my_last_pk;
would return the PK of the record you just inserted in a column called my_last_pk.
Note that this is session specific so if you and someone else both insert a new record at more or less the same time you would each get back your own inserted PK.
So my answer comes from both ComputerVersteher and User2834566 info.
I had to run two queries, both as passthrough and running on the same db instance to make sure it returned the right value:
Dim strSQL As String
Dim qdf As DAO.QueryDef
Dim db As DAO.Database
Dim rst As DAO.Recordset
strSQL = "INSERT INTO medstome_masterdb.tblChemists (chemName) VALUES ('newchem')"
strGETID = "SELECT ##IDENTITY"
Set db = CurrentDb
With db
Set qdf = db.CreateQueryDef("")
With qdf
.ReturnsRecords = False
.Connect = oCon
.SQL = strSQL
.Execute
End With
With qdf
.ReturnsRecords = True
.Connect = oCon
.SQL = strGETID
Set rst = .OpenRecordset(dbOpenSnapshot)
gPxID = rst(0)
Debug.Print gPxID
End With
End With
This works perfectly!
Thanks to the guys responding and helping

Column count does't not match value count at row 1

I'm having a problem about my code, i already tried to put the specified table for each column, In which part of my code was having a problem?
clientid = clientid.Substring(0, 3)
rnd = random.Next(100, 999)
clientid = clientid & "-" & Format(Now, "MMdd") & "-" & rnd
query = "SELECT COUNT(*) FROM tbl_clients WHERE clients_Record_Num ='" & clientid & "'"
sqlcmd = New MySqlCommand(query, conn)
chkclientid = sqlcmd.ExecuteScalar()
While chkclientid > 0
clientid = clientid.Substring(0, 3)
rnd = random.Next(100, 999)
clientid = clientid & "-" & Format(Now, "MMdd") & "-" & rnd
query = "SELECT COUNT(*) FROM tbl_clients WHERE clients_record_num ='" & clientid & "'"
sqlcmd = New MySqlCommand(query, conn)
chkclientid = sqlcmd.ExecuteScalar()
End While
query = "Insert into tbl_clients(clients_record_num,clients_client_id,clients_name,clients_contact_number,clients_address,clients_industry,clients_status,clients_delegate,clients_notes) values ('" & clientid.Substring(0, 3) &_ "-" & dttime & "-" & rnd &_ "','" & clientid & _
"', '" & txtClientName.Text & "','" & txtClientContactNum.Text & "','" & txtClientAddress.Text & _
"','" & cmbIndustry.Text & "', '" & cmbStatus.Text & "', '" & cmbDelegate.Text & "','" & txtNotes.Text & "','0')"
sqlCommand.Connection = conn
sqlCommand.CommandText = query
sqlCommand.ExecuteNonQuery()
As #jmcilhinney commented, change your insert query to use parameters as it will be easier to read and to ensure that the number of values matches the number of columns.
Here's some 'template' code for you to expand on:
Dim InsertCmdText As String =
"Insert into tbl_clients(clients_record_num,clients_client_id,clients_name,clients_contact_number,clients_address,clients_industry,clients_status,clients_delegate,clients_notes) " &
"values (#clients_record_num,#clients_client_id,#clients_name,#clients_contact_number,#clients_address,#clients_industry,#clients_status,#clients_delegate,#clients_notes)"
Dim SqlConnectionString As String = "Your Connection Info"
Using cmd As New SqlCommand(InsertCmdText, New SqlConnection(SqlConnectionString))
Try
cmd.Parameters.AddWithValue("#clients_record_num", "Value Needed")
cmd.Parameters.AddWithValue("#clients_client_id", "Value Needed")
cmd.Parameters.AddWithValue("#clients_name", "Value Needed")
'repeat above for all params
cmd.Connection.Open()
cmd.ExecuteNonQuery()
Catch ex As Exception
'Handle your exception
Finally
cmd.Connection.Close()
End Try
End Using
Alternatively use Parameters.Add instead of AddWithValue. For discussion on merits of each, see SqlCommand Parameters Add vs. AddWithValue

Make textbox null if empty

hello I have a userform in excel which is connected to mysql server.
everything works except when I leave the textbox for date empty, I get an error that the value for date is incorrect
on further research I found that the textbox return zero length string when empty and mysql allows only null.
Is there anyway to set the textbox as null when I click on the save button.
Heres my attempt at a solution, hopefully this will help.
Basically its a quick check to see if the textbox in question is empty, and if so, then make it null:
If textbox1.value = "" then
textbox1.value = null
end if
Finally a solution, but this will be a pain in the b, if you have 20 date columns. Unfortunately I have 20 date columns..:(
This is the code which for me, hope this helps someone in the future
Private Sub CommandButton1_Click()
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
strCon = "Driver={MySQL ODBC 5.3 Unicode Driver};Server=localhost;Database=sample;" _
& "User=root;Password=Password;Option=3;"
cn.Open strCon
If txt5.Value = "" Then
SQLStr = "insert into sample.details (ID,Name,Age,Gender,Date_of_Birth) values ('" & txt1.Value & "', '" & txt2.Value & "','" & txt3.Value & "','" & txt4.Value & "',Null);"
cn.Execute SQLStr
Else
SQLStr = "insert into sample.details (ID,Name,Age,Gender,Date_of_Birth) values ('" & txt1.Value & "', '" & txt2.Value & "','" & txt3.Value & "','" & txt4.Value & "','" & Format(txt5.Value, "yyyy-mm-dd") & "');"
cn.Execute SQLStr
End If
End Sub

Syntax error (missing operator) in query expression in VBA in MS Access

I get the following error message: 3075 missing operator in query expression
here a short snippet of the code:
Dim dbs As Database
Set dbs = CurrentDb()
dbs.Execute "DELETE FROM TempTable_Entity_mapping_DEFSET_Selection;"
Do While Not rsDEFSET.EOF
Debug.Print rsDEFSET.Fields.item("RESULT").Value
MIP = rsDEFSET.Fields.item("FK_DIM_MBR_ITEM").Value
KPIName = rsDEFSET.Fields.item("SHORTNAME_MBR").Value
ID = rsDEFSET.Fields.item("RESULT").Value
DefSetName = rsDEFSET.Fields.item("KPI_DEFSET_NAME")
Scenarios = rsDEFSET.Fields.item("SCENARIOS")
fillTempTab = "INSERT INTO TempTable_Entity_mapping_DEFSET_Selection (MIP, KPIName, ID, DefSetName, Scenarios) VALUES ('" & MIP & "','" & KPIName & "','" & ID & "','" & DefSetName & "','" & Scenarios & "');"
Debug.Print fillTempTab
dbs.Execute fillTempTab
rsDEFSET.MoveNext
Loop
Looks like you're missing what you want to delete in your SQL statement
Your first query should read
DELETE * FROM TempTable_Entity_mapping_DEFSET_Selection;

Adding data from Excel to Mysql via VBA

UPDATED QUESTION...SEE BELOW
I have an excel sheet which accesses a MySQL db as a backend....
I insert new records into MySql the following way, but I am not sure if this is the best way.
For rowline = 1 To 50
strSQL = myquerystring (INSERT 5 columns per excel row)
rs.Open strSQL, oConn, adOpenDynamic, adLockOptimistic
Next rowline
Basically the query string goes through each row in excel sheet (from 1 to 50) and the data on certain cells are added to the sql query and then inserted with rs.Open ....
(each row has some 5 columns which are inserted as a record)
Everything runs well, however I just want to know if there is a faster way (just one INSERT query), inserting all 50 (and 5 columns on each), from row 1 to 50, all at once.
At the moment it is doing 50 individual INSERT queries, so I am trying to reduce that to 1 but I don't know if it is possible.
NEW INFORMATION:
Hi, following your advice and links (thanks!) and some Googling, I ended up with the following code...
It works fine, HOWEVER to INSERT 100 rows it takes approx 15 seconds....this is far too much.
I am hoping I can get some code/ideas on how to Execute the query once, (inserting all 100 rows in one hit).
Please note that I am a beginner on this so if you can stir me into some samples on how it should be done it will be much appreciated.
Public Sub INSERT_to_MySQL()
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim strSQL As String
app_enable_false
On Error GoTo no_DB_connection_error
resume_after_connecting:
Set cmd = New ADODB.Command
cmd.ActiveConnection = oConn
' LOOP and INSERT the data
' 100 rows take approx 15 seconds to INSERT
For rowcursor= 1 To 100
the_table = "`global`.`filesaved` "
strSQL = "INSERT INTO " & the_table & " (Client_Name, OriginCity, DestinationCity, ValidFrom, ValidTo, Quote_Number, Cost1, Cost2, Cost3) "
strSQL = strSQL & " VALUES ('" & esc(Range("BB" & rowcursor)) & "','" & esc(Range("BC" & rowcursor)) & "','" & esc(Range("BD" & rowcursor)) & "','" & Format(Range("BE" & rowcursor), "yyyy-mm-dd") & "','" & Format(Range("BF" & rowcursor), "yyyy-mm-dd")
strSQL = strSQL & "','" & esc(Range("BH" & rowcursor)) & "','" & esc(Range("BJ" & rowcursor)) & "','" & esc(Range("BK" & rowcursor)) & "','" & esc(Range("BJ" & rowcursor)) & "')"
cmd.CommandText = strSQL
cmd.Execute
Next rowcursor
app_enable_true
Exit Sub
no_DB_connection_error:
ConnectDB
GoTo resume_after_connecting
End Sub
I would move the open command outside the loop, then use the Execute method to do the inserts in the loop. You don't want to do an open on the database every time.
Here's a good page of ADO methods.
Here's a question on Batch Inserting (and Updating).
EDIT: Looking at Remou's link in his comment, I realized that you probably don't even need the open. Just use the Execute method for the Inserts.
Find below a process which works, in case someone else has in future same problem.
Might not be the best solution but 100 records are saved all at once in less than a second, which is what I was after. Also there is only one INSERT query done (instead of 100 different ones for each row.
Thanks to all for your guidance.
Dim conn As ADODB.Connection
Dim cmd As ADODB.Command
Dim rst_recordset As ADODB.Recordset
Dim strSQL As String
Dim strSQL2 as string
On Error GoTo no_DB_connection_error
resume_after_connecting:
Set cmd = New ADODB.Command
cmd.ActiveConnection = oConn
' LOOP and INSERT the data
lastrow = Range("BB65536").End(xlUp).Row
the_table = "`global`.`filesaved` "
strSQL = "INSERT INTO `global`.`filesaved` " & " (Client_Name, OriginCity, DestCity, ValidFrom, ValidTo, Quote_Number, Cost1, Cost2, Cost3) VALUES "
strSQL2 = ""
For excel_row = 1 To lastrow
strSQL2 = strSQL2 & " ('" & cells(excel_row,1) & "','" & cells(excel_row,2) & "','" & cells(excel_row,3) & "','" & cells(excel_row,4) & "','" & cells(excel_row,5) & "','" & cells(excel_row,6) & "','" & cells(excel_row,7) & "','" & cells(excel_row,8) & "','" & cells(excel_row,9) & "') ,"
next excel_row
strSQL = strSQL & strSQL2
Mid(strSQL, Len(strSQL), 1) = ";" ' gets rid of the last comma
cmd.CommandText = strSQL
cmd.Execute
If I run a statement and do not expect a reply back, I usually go for the Command object in VBA.
This code worked for me
Sub insertdata()
Dim year As String
Set rs = CreateObject("ADODB.Recordset")
Database_Name = Range("b3").Value ' Name of database
User_ID = Range("b4").Value 'id user or username
Password = Range("b5").Value 'Password
Server_Name =Range("b2").Value
' Query for fetching Maximum Date
' LOOP and INSERT the data
lastrow = Range("BB65536").End(xlUp).Row
the_table = "`admin`.`test` "
strSQL = "INSERT INTO `drawing`.`test` " & " (tests,test2) VALUES "
strSQL2 = ""
For excel_row = 1 To 100
strSQL2 = strSQL2 & " ('" & Cells(excel_row, 1) & "','" & Cells(excel_row, 2) & "') ,"
Next excel_row
strSQL = strSQL & strSQL2
Mid(strSQL, Len(strSQL), 1) = ";" '
' ADODB connection
Set Cn = CreateObject("ADODB.Connection") 'NEW STATEMENT
Cn.Open "Driver={MySQL ODBC 5.1 Driver};Server=" & Server_Name & ";Database=" & Database_Name & _
";Uid=" & User_ID & ";Pwd=" & Password & ";"
rs.Open strSQL, Cn, adOpenStatic
Dim myArray()
End Sub