How do I fetch data from Access database records and display/save them as textboxes/variables in VB.net? - vb.net

coding noob here. I'm looking for help after hours of googling and watching YouTube tutorials provided no success. I've also tried looking at many of the posts on this website. I keep running into the same problem.
In Visual Studio I am attempting to create a solution with VB.net, it is currently successfully linked to an Access Database with which I can view, add, edit, and save records live.
I am trying to fetch data from the Access database based on a search of one of the fields, and then save that data as a variable.
(Code shown below)
Upon attempting to click the search button, I received the following exception: System.Data.OleDb.OleDbException: 'Syntax error (missing operator) in query expression 'First Name'.'
I believe it is because my field names are two words, but I have no idea how to fix this. Just typing it with one word gives this exception instead:
System.Data.OleDb.OleDbException: 'No value given for one or more required parameters.'
I have been completely unable to make progress despite watching multiple different versions of tutorials on how to perform this. Could someone please help me out?
Here is the code:
Public Class FormTraits
Private Sub FormTraits_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub FNButton_Click(sender As Object, e As EventArgs) Handles FNButton.Click
Dim conn As New OleDbConnection
conn.ConnectionString = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Access Database.accdb")
conn.Open()
Dim strsql As String
strsql = "select ID, First Name, Last Name from PlayerData where First Name=" + TextBoxSearch.Text + ""
Dim cmd As New OleDbCommand(strsql, conn)
Dim myreader As OleDbDataReader
myreader = cmd.ExecuteReader
myreader.Read()
TextBoxFirstName.Text = myreader("First Name")
TextBoxLastName.Text = myreader("Last Name")
TextBoxID.Text = myreader("ID")
conn.Close()
End Sub
End Class

You should avoid using names including spaces or other special characters for tables, columns, etc, in your database. Just as you would do for a variable name or the like in VB - and as you have done for your table name - you should name your columns FirstName and LastName. If you must include spaces or other special characters, you must escape the identifiers in your SQL code. You also need to wrap text literals in single quotes, much as you wrap them in double quotes in VB:
strsql = "SELECT ID, [First Name], [Last Name] FROM PlayerData WHERE [First Name] = '" & TextBoxSearch.Text & "'"
It would be better if you used parameters instead of string concatenation, but that's beyond the scope of this question.

Related

Select data from an ODBC connection into a MS Access database

A little background first. Where I work we have limited access to programming tools. We have access to the Microsoft Office Suite and therefore most of our projects are created in Access even though there are better solutions out there. We recently received access to Visual Studio 2013 and I am interested in converting some of our more heavily used tools into VB.NET projects.
I have a good understanding of VBA after using it for so many years, however, converting to VB.NET is definitely a change and although I understand the concept of it, many of the functions I used in the past do not exist in VB.NET.
Which leads me to the following question.
How do I connect to one database, an ODBC connection, then put selected fields from a table in that database to a table in a Microsoft Access database?
Here is my current code.
Imports System.Data.Odbc
Imports System.Data.Odbc.OdbcCommand
Imports System.Data.OleDb
Public Class Form1
Dim conn As OdbcConnection
Dim connBE As OleDb.OleDbConnection
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Call Connect_SLICWave()
Call Connect_Backend()
Dim sqlInsert As String = "INSERT INTO tblUOCs (EIAC,LCN,ALC,UOC) SELECT DISTINCT Trim(EIACODXA),Trim(LSACONXB),Trim(ALTLCNXB),Trim(UOCSEIXC) FROM ALAV_XC"
Dim beCmd As New OleDb.OleDbCommand(sqlInsert, connBE)
beCmd.ExecuteNonQuery()
End Sub
Private Sub Connect_SLICWave()
Dim connectionString As String
connectionString = "Dsn=slic_wave;uid=userid;pwd=password"
conn = New OdbcConnection(connectionString)
End Sub
Private Sub Connect_Backend()
Dim connectionStringBE As String
connectionStringBE = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\database.accdb"
connBE = New OleDb.OleDbConnection(connectionStringBE)
End Sub
End Class
Clearly this is not going to work. I have tried a few things based on examples on the Internet but have been unable to piece together any kind of code that works.
When using the Access database I would simply link to the tables in both the ODBC connection and the backend Access database and then I could use DoCmd to run SQL to move data as needed, however with VB.NET I don't have that luxury. Perhaps I am going about this all wrong due to my lack of knowledge with Visual Studio.
Is there a better way to accomplish my end goal? I need to be able to refer to the data in the ODBC connection and then store it somewhere so that I can output a specific dataset to the end user. Can/should I use a DataSet or DataTable? How much data can be stored in a DataSet/DataTable before the program would become unstable? The data used in this process can be quite excessive at times.
Typically the user would send the tool some criteria with 4 or 5 fields worth of data. The tool will then turn around and take that criteria to get the proper dataset from the ODBC connected database using joins on about 5 to 7 tables and returns one set of data to the user. Yes, it is a bit excessive, but that's the requirement.
I hope I am explaining this well enough without being too generic. The nature of my business prevents providing specific examples.
Sorry for being longwinded and I appreciate any effort that goes into helping me solve this issue. If there is anything that needs to be clarified please let me know and I will try to explain it more clearly.
You may find it helpful to be aware that when you run a query against the Access Database Engine from a .NET application you can use ODBC references in your queries and the engine will perform the required ODBC connections for you. In effect, these are temporary "on the fly" ODBC linked tables created for that specific query.
Say we have a table named [product] in SQL Server
id name
-- -----
1 bacon
2 tofu
and we can reach that SQL Server instance via an ODBC DSN named "myDb". We can reference that table from an Access query as
[ODBC;DSN=myDb].[product]
So, for example, if we want to query an Access table named [Orders]
OrderID ProductID Qty Units OrderDate
------- --------- --- ----- ----------
1 1 3 pound 2016-10-17
and pull in the product names from the SQL Server table named [product] we can do this in VB.NET:
Dim myConnectionString As String =
"Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source=C:\Users\Public\Database1.accdb;"
Using conn As New OleDbConnection(myConnectionString)
conn.Open()
Dim sql As String =
"SELECT p.name, o.Qty, o.Units " +
"FROM " +
"Orders o " +
"INNER JOIN " +
"[ODBC;DSN=myDb].[product] p " +
"ON p.id = o.ProductID"
Using cmd As New OleDbCommand(sql, conn)
Using rdr As OleDbDataReader = cmd.ExecuteReader
While rdr.Read
Console.WriteLine("{0} {1}(s) of {2} ", rdr("Qty"), rdr("Units"), rdr("name"))
End While
End Using
End Using
End Using
which prints
3 pound(s) of bacon
First of all, I need to ask about the original source for your SLICWave ODBC connection. Is it still in Access, or are you perhaps pulling from Sql Server or similar at this point? ODBC is going to pass your command statement on to the original source, and if you're using Sql Server now, instead of Access, some of the SQL syntax will change on you.
For the remainder of the question, I'll assume the SQL you have will work if executed. If it turns out you need help converting that to T-SQL for SQL Server, open a separate question limited to that specific problem.
That out of the way, I'm now going to limit my scope to this statement:
I need to be able to refer to the data in the ODBC connection and ... output a specific dataset to the end user.
What you want to do is put a DataGridView control on your form (I'll use the default DataGridView1 name for now). Then make the form code look like this:
Imports System.Data.Odbc
Imports System.Data.Odbc.OdbcCommand
Imports System.Data.OleDb
Public Class Form1
Private Property SLICWaveConnectionString As String = "Dsn=slic_wave;uid=userid;pwd=password"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim sql As String = "SELECT DISTINCT Trim(EIACODXA),Trim(LSACONXB),Trim(ALTLCNXB),Trim(UOCSEIXC) FROM ALAV_XC"
Dim dt As New DataTable
Using cn As New OleDb.OleDbConnection(SLICWaveConnectionString), _
cmd As New OleDb.OleDbCommand(sql, cn)
da As New OleDb.OleDbDataAdapter(cmd)
da.Fill(dt)
End Using
DataGridView1.DataSource = dt
End Sub
End Class
Imports System.Data.OleDb
Public Class Form1
Public con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\stores\Stock.accdb")
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
con.Open()
Dim sql As String = "SELECT * FROM Stock"
Dim dt As New DataTable
Dim cmd As New OleDbCommand(sql, con)
Dim da As New OleDbDataAdapter(cmd)
da.Fill(dt)
DGV.DataSource = dt
con.Close()
End Sub
End Class

Update button error

Our program when I click update button it updates all the data in the data grid view, what's wrong with our codes?
This is our code
Private Sub btnUpdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdate.Click
con.ConnectionString = ("server=localhost;user id=root;password=;database=sample4")
Try
con.Open()
With cmd
.Connection = con
.CommandText = "UPDATE inventory SET product_name='" & txtPN2.Text & "',product_quantity='" & txtQuan2.Text & "',date='" & txtDate2.Text & "' WHERE 1"
result = cmd.ExecuteNonQuery
If result = 0 Then
MsgBox("Data has been already updated!")
Else
MsgBox("Successfully updated!")
.CommandText = "Select product_name,product_quantity,date from inventory"
txtPN2.Clear()
txtQuan2.Clear()
txtDate2.Clear()
txtPN2.Focus()
End If
End With
Catch ex As Exception
MsgBox(ex.Message)
End Try
con.Close()
End Sub
There are a lot of errors here, both logical and bad practices at work.
Starting from the logical errors first:
What do you think this statement does? WHERE 1 (I don't even know if it is accepted by your database but suppose that it works). It doesn't locate a precise record to update, it let every record in your table to receive the same values specified in the SET list. You need to pass a key to identify a precise record to update. Something like WHERE KeyField=KeyValue where KeyField is the name of a column in your table Invetory whose values are unique so just one record is selected for the update
Second logical problem: If result = 0 Then this is wrong because the result of ExecuteNonQuery is the number of records updated/inserted/deleted. In your case the UPDATE sql updates always a record if it finds one. It update the record also if the values are the same as before. Zero instead means that no record has been found by the WHERE clause (after fixing it in the first step). Thus if you get zero as result then no record exists in your table that match the WHERE clause.
Now the bad practices.
SET product_name='" & txtPN2.Text &.....
This is a string concatenation that builds an sql statement. Wrong on many levels. If one of your textboxes contains a single quote the whole text becomes syntactically invalid. Finally a malicious user could write anything in those textbox and create an Sql Injection hack that could destroy your database or grab sensitive informations. You should use a parameterized query
.CommandText = "UPDATE inventory SET product_name=#prod " & _
",product_quantity=#qty,date=#dt WHERE keyField=#kvalue"
.Parameters.Add("#prod", SqlDbType.NVarChar).Value = txtPN2.Text
.Parameters.Add("#qty", SqlDbType.Int).Value = Convert.ToInt32(txtQuan2.Text)
.Parameters.Add("#qty", SqlDbType.DateTime).Value = Convert.TODateTime(txtDate2.Text)
.Parameters.Add("#kvalue", SqlDbType.Int).Value = kvalue
result = cmd.ExecuteNonQuery
Second bad practice: Keeping global objects for connection and commands. These are disposable objects, they should be used in a well know pattern. Create, Use, Destroy to free as soon as possible precious system resources. Keeping them global gains to you nothing and you are at risk to leak resources. Keep global (or better read from the app.config) just the connection string and apply the using statement around the connection and the command

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 populate a combobox in vb.net with filtered data from an msaccess table

I would really appreciate any help I can get.
My problem is that I have Combobox1 bound to a BindingSource and the DataMember and ValueMember property linked and working. For the life of me I do not know how to use the value (selected valuemember) of Combobox1 to filter the results I show on Combobox2. I am desperate for a simple way to do this.
my failing code is below
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim conn As New SqlConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\Database1.mdb") 'This line fails
Dim strSQL As String = "SELECT * FROM Questions WHERE Section='" & ComboBox1.ValueMember & "'"
Dim da As New SqlDataAdapter(strSQL, conn)
Dim ds As New DataSet
da.Fill(ds, "Disk")
With ComboBox2 'Here i try to populate the combobox2
.DataSource = ds.Tables("Questions")
.DisplayMember = "Question_String"
.ValueMember = "Question_Code"
.SelectedIndex = 0
End With
End Sub
I keep getting a system level error as follows
{"Keyword not supported: 'provider'."}
I have tried a few other options but the errors I get seem more cryptic can someone please help me on this. I will appreciate it a lot.
Dim conn As New OleDBConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source='|DataDirectory|\Database1.mdb'")
Also your query has to use a string not an object so try...
Dim strSQL As String = "SELECT * FROM Questions WHERE Section='" & ComboBox1.ValueMember.toString & "'"
Because you are using a Provider for a connection that doesn't need it because the provider should be an SQL driver.
I don't know what database you are using (well, the file is an access file), but you need to check you have the correct connection string
see http://www.connectionstrings.com/sql-server-2008#p2
Here are a couple of observations about your code that I hope you find helpful:
First, you might want to look at this MSDN help on how to move your database connection string out of the code and into a configuration file. This is especially important for your code to work to work more seemlessly across different environment (dev box, staging, production, etc) - Connection Strings and Configuration Files (ADO.NET)
I also noticed that you never explicitly open or close the connection. Per this entry on stack overflow, you should be ok, but keep in mind that if you happen to change the code to explicitly open the connection you will also need to close it.
I also noticed that you aren't using a parameterized query. This makes your code vulnerable to a SQL Injection attack. Here is a link to a blog posting by Scott Guthrie 'Tip/Trick: Guard Against SQL Injection Attacks'. You never know who may copy and paste your block of code with this bad practice.
Finally, you do the following query (with appropriate mods from other answers:
Dim strSQL As String = "SELECT * FROM Questions WHERE Section='" & ComboBox1.ValueMember.toString & "'"
And subsequently only use Question_String, and Question_Code in your code. You might want to consider changing your query to only pull the columns you need. This is especially helpful when you have tables with many columns. Otherwise you will needlessly pull data your code never actually needs. So your query would become:
Dim strSQL As String = "SELECT Question_String, Question_Code FROM Questions WHERE Section='" & ComboBox1.ValueMember.toString & "'"

Recordsets in VB.NET

All,
Trying to implement a recordset approach in VB.NET and (with the wonderful help of this community) have gotten to the point where things almost run. :)
Code:
Dim strSQL As String
Dim rsMaster As New ADODB.Recordset
strSQL = "select * " & "from tblDQ " & "order by xid, xcode, xDOS"
rsMaster.Open(strSQL, objConn, adOpenForwardOnly, adLockOptimistic)
The last line throws an exception while attempting to execute the rsMaster.Open line:
COM Exception was unhandled
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
Any ideas? Changing the cursor type or lock type doesn't seem to do any good, and the types specified above are available as options when coding the line. I've (on a WAG) added the following lines to the project:
Imports ADODB.LockTypeEnum
Imports ADODB.CursorTypeEnum
with no luck.
TIA!
Dave
Some ideas:
Does the SQL statement work in a "pure" database tool? (The &s looks a bit strange, but I assume that's a formatting issue in SO.)
The select * should work, but try a specific simple column (a short string or an integer), maybe there is an issue with a "tricky" column data type.
Do you have the objConn declared and a proper connection opened?
Some more ideas:
As you get the error when you execute the statement it seems that there is a problem with your statement. Is there a really simple SQL statement that will work in your scenario? (no order by, just a column, ..)
Try the statement from within MSAccess using the same connection parameters you are using in your VB.NET program. Maybe you are using a different user from within your program, maybe you have to qualify the table name etc.
If you say the connection is working fine, what did you do using the connection? Was there anything requiring access to the DB?
Ok, if removing the adOpenForwardOnly and the adLockOptimistic parameters doesn't change anything, how about changing the code slightly to use the Execute Method of the Connection object?
rsMaster.Open(strSQL, objConn, adOpenForwardOnly, adLockOptimistic)
Becomes
rsMaster = objConn.Execute(strSQL)
Not sure about your connection. You have an Access tag, but mentioned you tested in SQL Server. If you are using an access .mdb file
Imports adodb
Public Class Form1
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim strSQL, strConn As String
Dim rsMaster As New ADODB.Recordset
Dim objConn As New ADODB.Connection
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\DQ\DQ.mdb"
objConn.Open(strConn)
strSQL = "select * " & "from tblDQ " & "order by xid, xcode, xDOS"
rsMaster.Open(strSQL, objConn, CursorTypeEnum.adOpenForwardOnly, LockTypeEnum.adLockOptimistic)
rsMaster.MoveFirst()
Me.Text = rsMaster("xcode").Value
rsMaster.Close()
rsMaster = Nothing
End Sub
End Class