VB.NET - Getting value from MySQL database and inserting it into Ms. Access (MDB) database - vb.net

I want to Export database from MySQL and import it to Ms. Access (MDB) database. I've tried to code a long LoC to process importing database into a DataTable variable and store the value into it.
This is my code for getting value from adm_users database on MySQL
a_query = "SELECT * FROM adm_users where uac_code='4' or uac_code='4A' or uac_code='1'"
a_da = New MySqlDataAdapter(a_query, db_conn)
a_da.Fill(a_ds, "adm_users")
a_dt = a_ds.Tables("adm_users")
and then i want to store a_dt value into MDB database with this code
For x = 0 To a_dt.Rows.Count - 1
b_query = "INSERT INTO user_login
(userid, username, password, uac) VALUES
('" + a_dt.Rows(x).Item("userid") + "', '" + a_dt.Rows(x).Item("username") + "', '" + a_dt.Rows(x).Item("userpwd") + "', '2')"
b_sql = New OleDbCommand(b_query, ms_conn)
b_sql.ExecuteReader()
Next
and then trying to find a string queries stored in b_query, it looks like this
INSERT INTO user_login
(userid, username, password, uac) VALUES
('admin', 'Varenicou', 'administrator', '2')
and then the return value is: "syntax error in INSERT INTO statement"
i found there's nothing wrong with the queries, so i replace b_query variable with simple query like "SELECT FROM user_login" and the return value is: "syntax error in SELECT * FROM statement"
maybe i'm too dumb to ask this question, but my opinion is that VB.NET thinks that i've already opened a connection to MySQL Database and must always on MySQL database. So, when i open database connection with Ms. Access it'll return value like that and VB.NET confused with "which database you wanna use?"
any idea for me to do this task? i've asked my friend for some suggestions, he said that i need to work with class, i also have another idea to work with another new project that doing this task for inputing into Ms. Access database by exporting MySQL database into CSV first.

EDIT:
Having reread your question, I can tell you that the specific issue you're having is due to the fact that "password" is a reserved word in Jet/Access SQL. Any time you want to use a reserved word as an identifier in SQL, you need to escape it. For Access, you do that by wrapping it in brackets, e.g.
INSERT INTO user_login (userid, username, [password], uac)
VALUES (#userid, #username, #password, #uac)
My original advice below still stands though.
ORIGINAL:
If you have a DataTable then you don't loop through it to save the data. Just as you make a single Fill call on a data adapter to retrieve data, so you make a single Update call to save data. How does it make sense to call ExecuteReader when there's nothing to read? At least call ExecuteNonQuery but even that is not ideal.
If you want to insert the data it contains then you have to configure the InsertCommand of the second data adapter. You also need all the DataRows in the DataTable to have a RowState of Added. To do that, you simply set AcceptChangesDuringFill to False on the first data adapter. When you call Fill, it adds all the rows and thus their RowState is Added. It then calls AcceptChanges, which sets all the RowStates to Unchanged. Tell it not to call AcceptChanges and you're ready to insert.
Here's an example of getting data from one database and inserting into another using two data adapters:
Dim table As New DataTable
Using sourceAdapter As New MySqlDataAdapter("SELECT Column1, Column2 FROM MyTable",
"source connection string here") With {.AcceptChangesDuringFill = False}
sourceAdapter.Fill(table)
End Using
Using destinationConnection As New OleDbConnection("destination connection string here"),
destinationCommand As New OleDbCommand("INSERT INTO MyTable (Column1, Column2) VALUES (#Column1, #Column2)",
destinationConnection),
destinationAdapter As New OleDbDataAdapter With {.InsertCommand = destinationCommand}
With destinationCommand.Parameters
.Add("#Column1", OleDbType.VarChar, 50, "Column1")
.Add("#Column2", OleDbType.Integer, 0, "Column2")
End With
destinationAdapter.Update(table)
End Using
As you can see, it's fairly simple stuff. One data adapter with a SelectCommand and another with an InsertCommand. There's nothing special about the adding of the parameters, but you do need to know about parameters in the first place. If you don't know how to use parameters with ADO.NET then you should learn immediately. You can find my own explanation here.

Related

How can i set the value from the last row in an specific column in a variable in VB.Net

I'm develop an application using forms in vb.net with visual studio 2019
I have code in the event click for one button
Dim oda As New OleDbDataAdapter
Dim ods As New DataSet
Dim consulta As String
Dim cadena As New OleDbConnection
Dim comando As New OleDbCommand
Try
cadena.Open()
comando = New OleDbCommand("Insert into QRQC (Nombre,NumControl,Fecha,Hora,Turno)" &
"values(txt_nombre,txt_numControl,lbl_fecha,lbl_hora,cBox_turno)", cadena)
consulta = "Select *From QRQC"
oda = New OleDbDataAdapter(consulta, cadena)
ods.Tables.Add("QRQC")
oda.Fill(ods.Tables("QRQC"))
Dim row As Integer
row = ods.Tables("QRQC").Rows.Count - 1
courrentId = ods.Tables("QRQC")(row)("ID_QRQC").ToString()
frm_newPt2.lbl_folioQRQC.Text = courrentId
cadena.Close()
Catch ex As Exception
MsgBox("Error al generar el registro en la base de datos", vbCritical, "Aviso")
Console.WriteLine(ex)
cadena.Close()
GoTo skip
End Try
Everything goes perfectly, but when I delete some record on my DB this part of the code always return the value 102
courrentId = ods.Tables("QRQC")(row)("ID_QRQC").ToString()
How can i solve this problem?
First of all, your insert command is wrong, and will not work.
You have "values(txt_nombre. etc etc."
But that is just a string and NOT the actual values from the form. So you are actually going to "instert txt_nombre" into that table and NOT the value of that label or text box on the form!!!
So you need to fix and get your insert command working FIRST.
And if this is just editing data then consider using the data binder, since navigation, editing, deleting and saving of data to/from the table can occur 100% automatic whiteout ANY code on your part.
so first up is to fix that insert command. You can't JUST use a string with the names of the controls else that would actually as noted try to insert the names of the controls as text and NOT the values of the controls.
And lets clean up a few other things. No need for a dataset, since a dataset is a SET of tables - we only dealing with one table (so use a data table).
But as noted, before we mess with data tables, we have to fix that insert command.
It will, can look like this:
Dim strSQL As String
strSQL = "Insert into QRQC (Nombre,NumControl,Fecha,Hora,Turno) " &
"VALUES(#nombre,#numControl,#fecha,#hora,#turno)"
Using cmdSQL As New OleDbCommand(strSQL,
New OleDbConnection(My.Settings.TestDB))
cmdSQL.Parameters.Add("#nombre", OleDbType.Integer).Value = txt_nombre.Text
cmdSQL.Parameters.Add("#numControl", OleDbType.Integer).Value = txt_numControl.Text
cmdSQL.Parameters.Add("#fecha", OleDbType.Integer).Value = lbl_fecha.Text
cmdSQL.Parameters.Add("#hora", OleDbType.Integer).Value = lbl_hora.Text
cmdSQL.Parameters.Add("#turno", OleDbType.Integer).Value = txt_nombre.Text
cmdSQL.Connection.Open()
cmdSQL.ExecuteNonQuery()
End Using
So you have to "replace" the string values in the sql with the ACTUAL values you are using.
You also don't show where/how you setup your connection to the database. I guessed that you used the applications settings and the connection builder - so you have to change TestDB to your actual connection that you used.
The above will thus get your insert command working.
At that point, you can post a new question in that after you do a insert, how to get the new autonumber primary key, or whatever else you wanted to do, but your insert statement as written will not work.
As noted, perhaps it better to use data bound controls. This will result in a Access like design experience, and you not having to write ANY code to edit a table in vb.net.
And it not clear if the control names I used are correct (or they are even controls on the form), but if they are, then ".Text" is required to grab the values. You have to of course change (check) that the control names I used and guessed are correct.
You also have to change the data type "integer" I used in above to the correct data types. For text I recommend you use .VarWChar

SQLite Inserts - How to Insert Any Text while Avoiding Syntax Errors using Parameterized Values

I'm curious to know a proper way to insert text strings into a database regardless of what characters are contained within the string. What I'm getting at is if I have a string for example that contains single quotes or any other character that is reserved as a 'special' SQL character.
The issue specifically that I'm dealing with is that I don't have control over the possible 'Text' that is being inserted into my database as they text is generated by my application.
One example of where my application fails to insert properly is when there's an error message that happens to contain single quotes. Single quotes are used by SQL statements insert text of course and so I can't insert text that also contains single quotes (outside of using ascii value char(##) function). The issue I'm dealing with is that I'm setting the output of my application to a string variable to then be inserted into my database so I can log activity whether that be standard output or catching errors.
How do I simply INSERT what's contained in my string variable while avoiding all of the SQL Special characters?
Do I need to manually account for all of the SQL Special characters and replace them in my string prior to insert? This sounds like a hit or miss and I'm hoping that there's something already built to accommodate this situation.
Sample Pseudo Code to get the point across:
Let's say an error occurred within the app and it needs to be logged. The error string could be:
Error String: "Error in function calculateStats() parameter 'pBoolStatCheck' is Null"
Now I assign to my string variable within my app and build up the SQL Insert string.
var insertString = "Error in function calculateStats() parameter 'pBoolStatCheck' is Null"
INSERT INTO outputLog(outputLogText)
VALUES ('insertString'); --This will Fail
--Fails due to the variable 'insertString' containing single quotes.
INSERT INTO outputLog(outputLogText)
VALUES ('Error in function calculateStats() parameter 'pBoolStatCheck' is Null');
In closing - since I have no control over the text that could be created by my application how do I account for all of the possible characters that could break my insert?
The code my current application encountering this issue is written in Visual Basic. The database I'm working with is SQLite.
The final solution based on answers received by this post:
Public Sub saveOutputLog(pTextOutput, pTextColor, pNumNewLines, plogType, pMethodSub)
Dim strTableName As String = "outputLog"
Dim sqlInsert As String = "INSERT INTO " & strTableName & "(" &
"outputLog, logColor, numNewLines, logType, method" &
") VALUES (#outputLog, #logColor, #numNewLines, #logType, #method);"
Try
'Open the Database
outputLogDBConn.Open()
'Create/Use a command object via the connection object to insert data into the outputLog table
Using cmd = outputLogDBConn.CreateCommand()
cmd.CommandType = CommandType.Text
cmd.CommandText = sqlInsert
cmd.Parameters.AddWithValue("#outputLog", pTextOutput)
cmd.Parameters.AddWithValue("#logColor", pTextColor)
cmd.Parameters.AddWithValue("#numNewLines", pNumNewLines)
cmd.Parameters.AddWithValue("#logType", plogType)
cmd.Parameters.AddWithValue("#method", pMethodSub)
'Execute the command using above Insert and added Parameters.
cmd.ExecuteNonQuery()
End Using 'Using outputLogDBComm
outputLogDBConn.Close()
Catch ex As Exception
outputLogDBConn.Close()
End Try
End Sub
This problem is very similar to the problem of preventing SQL Injection vulnerabilities in your code. Queries are very easy to break, and while yours breaks in a way that is harmless and annoying, these can be taken to levels where certain inputs can completely destroy your database!
One of the best ways to approach this is by using parameterized queries. This approach is pretty simple; you write the query first with 'placeholders' for the parameters you will send. Once you are ready in your program you can then 'bind' those parameters to the placeholders.
It would look something like the following:
Dim command = New SqlCommand("INSERT INTO outputLog(outputLogText) VALUES (#stringToInsert)", connection);
.
.
.
code
.
.
.
command.Parameters.AddWithValue("#stringToInsert", errorMessage)
.
.
.
execute query
In the above you see that #stringToInsert is the placeholder which is only bound at a later time. It doesn't matter what the variable errorMessage contains, since it will not cause the query to function in a way where the input causes it to potentially break.
There are a lot of resources on this:
https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.prepare?view=netframework-4.7.2
Database objects like connections not only need to be closed but also disposed. A Using block will ensure this will happen even if there is an error.
The .Add is better than .AddWithValue for a number of reasons. See https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/ and http://www.dbdelta.com/addwithvalue-is-evil/
The parameters of .Add are the name of the parameter, the datatype in the database and optionally the size of the field. You will need to check the database for the last 2.
Open the connection at the last minute befor the execute.
If you are using OleDb with Access, you need to make sure the parameters are added in the same order as they appear in the sql statement.
Using cn As New SqlConnection("Your connection string")
Using cmd As New SqlCommand("INSERT INTO outputLog(outputLogText) VALUES (#outputLogText);", cn)
cmd.Parameters.Add("#outputLogText", SqlDbType.VarChar, 100).Value = TextBox1.Text
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Using

Visual Basic Project fails to update Microsoft Access database

I have created a database that holds 3 values, the ID, UserName, and Score. I need to create a new entry to this database when the save button is clicked. My program needs to create a new row with the Username and score provided by the application.
This is my code to update an existing database:
Private Sub ButtonSaveScore_Click(sender As Object, e As EventArgs) Handles ButtonSaveScore.Click
provider = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="
dataFile = "F:\Documents\Class Documents\CSC289 - K6A - Programming Capstone Project\Project\Scoreboard.accdb"
connString = provider & dataFile
myConnection.ConnectionString = connString
Using con As New OleDbConnection(connString),
cmd As New OleDbCommand("UPDATE [Scores] SET [UserName] = ?, [Score] = ? WHERE [ID] = ?", con)
con.Open()
cmd.Parameters.Add("#ID", OleDbType.Char).Value = "NEW"
cmd.Parameters.Add("#UserName", OleDbType.Char).Value = playerName
cmd.Parameters.Add("#Score", OleDbType.Char).Value = wins
cmd.ExecuteNonQuery()
End Using
End Sub
I get
oledb exception was unhandled
It highlights cmd.ExecuteNonQuery() and says data criteria mismatch.
Can someone give me advice to get this working?
You have a couple of issues there. Firstly, at least one of your parameters is the wrong data type. Secondly, your parameters are in the wrong order.
The Jet and ACE OLE DB providers only partially support named parameters, in that they allow you to use names so that your code can be clearer but they ignore the names and just use the positions. That means that you need to add the parameters to your OleDbCommand in the same order as they appear in the SQL code. You're not doing that so you have one issue there, although that's not the direct cause of your error message.
Even if those providers did fully support named parameters though, you're not using names in your SQL code. That means that there would be no way to match up parameters by name anyway, so how did you think that adding them in the wrong order wouldn't be an issue?
Given that all three of your parameters are specified as the same data type though, the incorrect order would not cause the error message you're seeing. If that data type was correct, you'd just find that the wrong data was saved to some of the columns, which would be even worse, i.e. appearing to work but not rather than just failing. You need to make sure that you use the correct OleDbType value for the column you're trying to save to. If your ID column in the database is specified to contain 32-bit numbers then you should be using OleDbType.Integer for the corresponding parameters. I'd also suggest using VarChar rather than Char unless your column is specifically fixed-width, which a Text column in Access is unlikely to be and I'm not sure even can be.

VB Access DB Update statement

I am new to this forum, please could you help me get this code to work, when i execute it, it simply does nothing and does not update the DB. If i remove the square brackets it gives an error: "SYNTAX ERROR in UPDATE statement"
Any help appreciated!
Dim connection As OleDbConnection
connection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=UserDB.accdb;Jet OLEDB:Database;")
connection.Open()
Dim pass As String
pass = txtconfirm.Text
Dim user As String
user = LoginForm.UsernameTextBox.Text
Dim query As String = "UPDATE [Users] SET [Password]= '" & pass & "' WHERE [Username]= '" & user & "';"
Dim command As New OleDbCommand(query, connection)
command.ExecuteNonQuery()
connection.Close()
Given your actual connection string, the database that will be updated is the one in the directory where your application starts. This means that if you work with a WinForms application this folder is \BIN\DEBUG or x86 variant. If there is not error then you could get the return value of the ExecuteNonQuery call to verify if a record has been updated or not
Dim rowsUpdated = command.ExecuteNonQuery()
MessageBox.Show("Record updated count = " & rowsUpdated)
If this value is not zero then your database has been updated and you are looking for changes in the wrong database. Check the one in the BIN\DEBUG folder.
In any case your code has big problems. If your variables user or pass contain a single quote, then your code will crash again because your string concatenation will form an invalid SQL. As usual the only workaround is to use a parameterized query
Dim pass = txtconfirm.Text
Dim user = LoginForm.UsernameTextBox.Text
Dim query As String = "UPDATE [Users] SET [Password]= #p1 WHERE [Username]= #p2"
Using connection = New OleDbConnection("...........")
Using command As New OleDbCommand(query, connection)
connection.Open()
command.Parameters.Add("#p1", OleDbType.VarWChar).Value = pass
command.Parameters.Add("#p2", OleDbType.VarWChar).Value = user
command.ExecuteNonQuery()
End Using
End Using
The parameterized approach has many advantages. Your query text is more readable, there is no misunderstanding between your code and the values expected by your database engine. And while not easy to exploit with MS-Access there is no problem with Sql Injection
I think Steve presents a much better approach for you coding this...
Let me just throw out a few more things:
The reason you can't take those brackets out is some of your column names are reserved words; just FYI.
Since you report "it does nothing..." when you execute, it sounds like you have a valid connection and sql syntax, in which case my next step would be to copy the sql command text while in debug mode, change it to a select and run it in your DB. You should get one result when you do. If not, either your criteria or field contents are not what you think they are...
Just change the Update table SET field-value ... to SELECT * FROM table and leave the WHERE clause as is.

How To Find Input String In Database

I want to find the text in textbox in my database. I wrote the code below. It finds numbers well, but when I want to find strings it gives a runtime error: invalid column name for example aaa, but aaa exists in column1 in my table.
What do you think about the problem?
cmd = New SqlCommand("select * from tbl where column1=" + TextBox1.Text)
cmd.CommandType = CommandType.Text
cmd.Connection = cnn
dad.SelectCommand = cmd
cmd.ExecuteNonQuery()
dad.Fill(ds)
dgv.DataSource = ds.Tables(0)
That's because the sql statement you send is not delimiting the TextBox1.Text value so you end up with this sql:
select * from tbl where column1 = aaa
and SQL Server treats aaa as a column name.
Regardless of that, you should be using a SqlParameter to avoid sql injection attacks:
cmd = New SqlCommand("select * from tbl where column1=#value")
cmd.CommandType = CommandType.Text
cmd.Paramaters.AddWithValue("#value", TextBox1.Text)
VB is not my primary language, so the syntax might be a little off, but you should be able to make it work.
Adritt is right, you must enclose the text to find within single quotes and, provided that very text doesn't contains single quotes, all is well - Apart for the risk of SQL attacks.
That being said, you are using an outdated, obsolete way of coding your app against the database.
You should definitively have a deep look at LINQ technology where:
You have no connection to open or close: its automatic
You don't have to cope with quotes, crlf and commas
You do not risk SQL attacks: queries are parameterised by the LINQ engine
You will benefit from intellisense againts the database objects: tables, views, columns
You get a straightforward result to use as the datasource!
For INSERT and UPDATE statements transactions are automatically enabled.
Example:
using ctx as new dataContext1
dim result = from r in ctx.tbl
where r.column1 = textBox1.text
dgv.datasource = result.tolist
end using
Intellisense:
When you type "ctx.", you are presented with the list of available tables!
When you type "r." you are presented with the list of column the table (or vieww) contains!
LINQ is not difficult to learn and you'll find tons of examples to help you, here and there on the web.
Last but not least, you can use the LINQ SQL-like syntax to query XML data, CSV files, Excel spreadsheets and even the controls in your form, or the HTML DOM document in ASP.NET!