OleDbDataAdapter doesn't like LIKE conditions - vb.net

I have some code to find the first DataRow in some DB Table for a matching WHERE condition and an ORDER BY sort order which looks like:
Public Function GetRow(SQL As String) As DataRow
If Not OpenConnection() Then Return Nothing
Dim DT As New DataTable With {
.Locale = Globalization.CultureInfo.InvariantCulture
}
Dim Cmd As New OleDbCommand(SQL, Connection, Transaction)
Try
Using Adapter As New OleDbDataAdapter With {.SelectCommand = Cmd}
Adapter.Fill(DT)
End Using
Catch Ex As OleDbException
MsgBox(Ex.Message)
Finally
CloseConnection()
End Try
If DT.Rows.Count = 0 Then
Return Nothing
Else
Return DT.Rows(0)
End If
End Function
Assume this is part of a class, so the functions OpenConnection and CloseConnection do what their names are promising. This also applies to the Variables Connection and Transaction. The Catch part is only temporarily in it to test if there is an exception. But there wasn't.
Then I have an Access Database with a Table named 'Players' and some guys in it, especially a guy named 'Fred Bauer', which fills the colums Name and Forename like Name:=Bauer, Forename:=Fred (just as example). Now I like to search for the first guy which name begins with B, so the SQL looks like:
SELECT * FROM Players WHERE [Name] LIKE 'B*' ORDER BY [Name]
And the code finds nothing. DT.Rows.Count will be 0. Hmmmmm?! I know that the guy is in there, the SQL should have found him. To test the correctness of the code I tried the same SQL Code directly in Access as a view and it works fine. It returns a view with Fred Bauer as one row.
Then I tried to make the counter test and find the guy directly with my code and with:
SELECT * FROM Players WHERE [Name] = 'Bauer' ORDER BY [Name]
This works fine. The correct DataRow is found and given back. WHAT?!!
It seems like the OleDbDataAdapter doesn't like LIKE conditions. Maybe someone can help me out and get it work also for LIKE conditions? Or if you have any suggestions to do it in a complete different way, it's welcome.

You shouldn't be using an OpenConnection and CloseConnection methods. Connections and other database objects should be local to the method where they are used so they can be disposed. There is nothing in this code that requires a transaction or DataAdapter.
As mentioned in comments use % for wildcard outside of Access.
Public Function GetRow() As DataRow
Dim SQL = "SELECT * FROM Players WHERE [Name] LIKE 'B%' ORDER BY [Name]"
Dim DT As New DataTable With {.Locale = Globalization.CultureInfo.InvariantCulture}
Try
Using con As New OleDbConnection("Your connection string"),
Cmd As New OleDbCommand(SQL, con)
con.Open()
DT.Load(Cmd.ExecuteReader)
End Using 'Closes and disposes the connection and command
Catch Ex As OleDbException
MsgBox(Ex.Message)
End Try
If DT.Rows.Count = 0 Then
Return Nothing
Else
Return DT.Rows(0)
End If
End Function

Related

how to inner join two tables or more tables from ms access database with vb.net?

I have three tables in access database and a Application in vb.net where i am trying to search data from all three tables by TextBox but it is giving error.can someone tell me how to do this?
enter code here
Private Sub check()
Dim Myconn As New OleDbConnection(constr)
Dim adapter As New OleDbDataAdapter()
Dim command As New OleDbCommand()
Dim sql = "select descriptionofgoods,remarks,mode from tabel1 INNER JOIN table2 ON tabel1.id = tabel2.id inner join tabel3 on tabel1.id = tabel3.id;"
Try
Myconn.Open()
dt.Clear()
If TextBox2.Text > "" Then
sql = sql & " and [id] = ? "
command.Parameters.AddWithValue("id", TextBox1.Text)
End If
command.Connection = Myconn
command.CommandText = sql
adapter.SelectCommand = command
adapter.Fill(dt)
If dt.Rows.Count > 0 Then
DataGridView1.DataSource = dt
DataGridView1.Refresh()
Else
MessageBox.Show("ITEM NOT FOUND")
End If
Catch exp As Exception
Throw exp
Finally
If Myconn IsNot Nothing Then Myconn.Close()
End Try
End Sub
A lot of your code is redundant and can be removed:
Using da as New OleDbDataAdapter("select descriptionofgoods,remarks,mode from tabel1 INNER JOIN table2 ON tabel1.id = tabel2.id inner join tabel3 on tabel1.id = tabel3.id", constr)
Dim dt = DirectCast(DataGridView1.DataSource, DataTable)
dt.BeginLoadData()
dt.Clear()
If Not string.IsNullOrEmpty(TextBox2.Text) Then
da.SelectCommand.CommandText &= " and tabel1.[id] = ? "
da.SelectCommand.Parameters.AddWithValue("id", TextBox1.Text) 'why is this TextBox1 when you tested textbox2 in the If?
End If
adapter.Fill(dt)
dt.EndLoadData()
End Using
Notes:
Use Using; you then don't need your Try/Finally
DataAdapter knows how to create and open a connection itself
Don't catch exceptions only to throw them again; it disrupts the stack trace. Dont put a catch at all if youre not going to catch anything; Try ... Finally is legal, Throw on its own is legal (doesn't disrupt stack trace)
Do not terminate an SQL with a semicolon if you want to add to it. Don't terminate a single statement SQL with a semicolon anyway
You have several tables with an ID column; Access might let you get away with not specifying which ID you're talking about but proper databases won't so get in the habit now of fully qualifying every column (in your select too)
See the comment about TextBox1/TextBox2
Please.. name your controls properly. "name of a type of object plus a serial number" is not a good name for anything; your name is Pankaj Babbar, not human105874274365. You name your local variables well but not your class level ones, which is definitely the wrong way round
To rename a control after you add it to a windows form, click on it, then change then text in the (Name) line of the property grid
Telling a datatable youre about to/have finished loading data improves performance
Bound controls update automatically (if you ever use BindingSource investigate the RaiseListChangedEvents setting too)

Visual Basic, Copying Success but does not Insert data into SQL TABLE

I have some problems here. I need help.
Recently, I have created a local database called stock.mdf and the application will be getting all the data from the hosting MySQL database into this local SQL Server database.
I am using sqlBulkCopy to inserting all the data. I have tried to view it after inserting. But when I close my application, I head back to check the table data. It does not inserted. Why is that?
Here is my code:
Here will be retrieving the data from the hosting
Dim connStr As String = "server=xxxx;user=xxx;database=xxx;password=xxxx;"
Dim conn As New MySqlConnection(connStr)
Dim cmd As New MySqlCommand
Dim Adapter As New MySqlDataAdapter
Dim StockData As New DataTable
Try
Dim SQL As String = "SELECT * FROM stock"
Console.WriteLine("Connecting to MYSQL.....")
conn.Open()
cmd.Connection = conn
cmd.CommandText = SQL
Adapter.SelectCommand = cmd
Adapter.Fill(StockData)
' StockViewGrid.DataSource = StockData
Catch ex As Exception
Console.WriteLine(ex.ToString())
Finally
conn.Close()
Console.Write("Done")
End Try
This will be the places where sqlBulkCopy working:
As well, I am trying to view from the stock table.
Dim Local_connectionStr As String = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|stock.mdf;Integrated Security=True"
Dim Local_conn As New SqlConnection(Local_connectionStr)
Dim Local_cmd As New SqlCommand
Dim Local_Adapter As New SqlDataAdapter
Dim Local_StockData As New DataTable
Try
Using sqlBulkCopy As New SqlBulkCopy(Local_conn)
'Set the database table name
sqlBulkCopy.DestinationTableName = "stock"
'[OPTIONAL]: Map the DataTable columns with that of the database table
sqlBulkCopy.ColumnMappings.Add("stockId", "stockId")
sqlBulkCopy.ColumnMappings.Add("id_android", "id_android")
sqlBulkCopy.ColumnMappings.Add("itemCode", "itemCode")
sqlBulkCopy.ColumnMappings.Add("quantity", "quantity")
Local_conn.Open()
sqlBulkCopy.WriteToServer(StockData)
Local_conn.Close()
End Using
Catch ex As Exception
Console.WriteLine(ex.ToString())
Finally
Local_conn.Close()
Console.Write("Done")
End Try
Try
Dim SQL As String = "SELECT * FROM stock"
Console.WriteLine("Connecting to MYSQL.....")
Local_conn.Open()
Local_cmd.Connection = Local_conn
Local_cmd.CommandText = SQL
Local_Adapter.SelectCommand = Local_cmd
Local_Adapter.Fill(Local_StockData)
StockViewGrid.DataSource = Local_StockData
Catch ex As Exception
Console.WriteLine(ex.ToString())
Finally
Local_conn.Close()
Console.Write("Done")
End Try
Since I can't comment (not enough points) I will put my thoughts here. Can you check that you got the expected data with a
Console.WriteLine(StockData.Rows.Count.ToString)
Console.ReadLine()
Also, your destination table doesn't have a PK that is auto increment, does it?
Sorry about the comment as an answer. (Untested code)
Unfortunately your code extracts are lacking headers etc, so are not complete, and I cannot be absolutely certain, BUT in your retrieving routine you seem to be declaring StockData as a local variable. This means that, although this may well be being filled with the data from MySQL, it is immediately discarded on exiting from this routine. Therefore the StockData variable in the sqlBulkCopy routine will be empty, and therefore will insert nothing. You need to fix your scope and make sure that the StockData read from MySQL is the same StockData used in SqlBulkCopy.

How do I create a dataset in VB.NET from this code?

I currently have the following code in my project which populates a DataGridView object with the results of an SQL query.
Sub PerformQuery(ByVal SQLText As String)
Dim DbConnection As New OleDb.OleDbConnection(createConnectionString)
Dim SQLQuery As String = SQLText
Dim Adapter As New OleDb.OleDbDataAdapter(SQLQuery, DbConnection)
Try
Using Table As New DataTable
Adapter.Fill(Table)
Table.Locale = Globalization.CultureInfo.InvariantCulture
DbConnection.Close()
DataGridView1.DataSource = Table
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Elsewhere in my project I can create a DataSet object using the code
Dim ds As New DataSet
And then extract data from it using code like:
MaxRows = ds.Tables("Dataset_Users").Rows.Count
Rather than populating a DataGridView, how can I use the PerformQuery code to create a dataset?
Thank you in advance for your help.
I think you are after the following:
Try
Dim ds As New DataSet
Using Table As New DataTable
Adapter.Fill(Table)
Table.Locale = Globalization.CultureInfo.InvariantCulture
DbConnection.Close()
DataGridView1.DataSource = Table
ds.Table.Add(Table)
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
Or as in your example you was after the Number of rows in the dataset you can do the same with the DataTable, For Example:
Try
Dim MaxRows As Integer
Using Table As New DataTable
Adapter.Fill(Table)
Table.Locale = Globalization.CultureInfo.InvariantCulture
DbConnection.Close()
DataGridView1.DataSource = Table
'' Getting the number of rows in the DataTable
MaxRows = Table.Rows.Count
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
Think in a more functional style. Return the table instead of setting to grid. While we're here, let's update the method so you don't have to write queries anymore that leave you wide open to sql injection attacks:
Function PerformQuery(ByVal SQLText As String, ByVal ParamArray Parameters() As OleDbParameter) As DataTable
Dim result As New DataTable()
Using cn As New OleDb.OleDbConnection(createConnectionString), _
cmd As New OleDb.OleDbCommand(SQLText, cn), _
Adapter As New OleDb.OleDbDataAdapter(cmd, cn)
If Parameters IsNot Nothing AndAlso Parameters.Length > 0 Then
cmd.Parameters.AddRange(Parameters)
End If
Adapter.Fill(result)
End Using
Return Result
End Function
Note that I also removed the error handling and locale code. You still need to do that stuff, but when you want to just return a datatable instead of interact directly with the user interface in a method you have effectively moved your code to a lower level of abstraction. When you do that, you probably don't want to deal with the error handling at this lower level any more; instead let the exceptions bubble up where you can handle them closer to the user interface.
Now you call the updated method like this:
Dim sql As String = "SELECT * FROM Customers WHERE CustomerID = ?"
Dim CustID As New OleDb.OleDbParameter("CustomerId", OleDbType.Integer)
CustID.Value = 123456
Try
DataGridView1.DataSource = PerformQuery(sql, CustID)
Catch Ex As Excpetion
MsgBox(Ex.Message)
End Try

Check if a table is empty on SQLite

I'm trying to adapt to VB.NET the code of the most voted answer from this post:
Sqlite Check if Table is Empty
Original code is
SQLiteDatabase db = table.getWritableDatabase();
String count = "SELECT count(*) FROM table";
Cursor mcursor = db.rawQuery(count, null);
mcursor.moveToFirst();
int icount = mcursor.getInt(0);
if(icount>0)
//leave
else
//populate table
My code looks like ('Only to have a message on the screen I will fill the If - Else code later')
Using conn As New SQLiteConnection("Data Source=myDataBase.sqlite;Version=3;foreign keys=true")
Try
conn.Open()
Dim emptyUserTable = "SELECT COUNT(*) FROM usersTable"
Dim cmdIsEmpty As SQLiteCommand = New SQLiteCommand(emptyUserTable, conn)
Try
Dim Answer As Integer
Answer = cmdIsEmpty.ExecuteNonQuery()
MsgBox(Answer)
Catch ex As Exception
MsgBox(ex.ToString())
End Try
End Using
But the "Answer" is allways -1, with empty table or not.
I donĀ“t know how to use getWritableDataBase because I get a
getWritableDatabase is not a member of SQLiteConnection
The same with rawQuery.
How can I check if usersTable is empty or not on VB.NET?
I've abstracted your code a little so it can be used for any table:
Private Function IsTableEmpty(tblName As String) As Boolean
Dim sql = String.Format("SELECT COUNT(*) FROM {0}", tblName)
Using conn As New SQLiteConnection(LiteConnStr)
Using cmd As New SQLiteCommand(sql, conn)
conn.Open()
Dim rows = Convert.ToInt32(cmd.ExecuteScalar())
Return rows = 0
End Using
End Using
End Function
Usage:
If IsTableEmpty("usersTable") Then
Console.Beep()
End If
Notes
The command object should be disposed when you are done with it, so it is used on a Using block.
There is not need to copy your connection string everywhere. You can define it once as a form/class level variable and reuse it everywhere
ExecuteScalar() gets the count back, then it is tested for 0 rows

Search records in database for those that match what a user enters

I'm trying to write a function that searches records in my database for the object of those that match the SearchCriteria. The functions parameters look like so:
RetrieveObject(SearchCriteria) As String (SearchCritera is a string aswell)
Right now for testing purposes I am using a console app that asks the user to search by first name.
Console.Writeline("Search by first name: ")
Dim firstName = Console.Readline()
I then use my function: RetrieveObject(firstName)
I want my function to show all the values (lastname, titlename, state, zip) for that particular person that was passed to the RetrieveObject function.
The problem I am having is that I cannot seem to understand how I'm going to match what the user enters with the value in the database.
If anyone could just put me in the right direction to help me understand how to accomplish this, I'd be so grateful!
Here is my code so far:
Private Function RetrieveObject(SearchCriteria As String) As String
Dim cn As OdbcConnection = New OdbcConnection(myCon)
Dim myQuery = "SELECT * FROM Applicant WHERE [strFirstName] LIKE '%son'"
Using com As New OdbcCommand(myQuery)
cn.Open()
com.Connection = cn
com.CommandType = CommandType.Text
com.CommandText = myQuery
com.Parameters.AddWithValue("#strFirstName", SearchCriteria)
Try
com.ExecuteReader()
Catch ex As Exception
MsgBox(ex.Message.ToString())
End Try
End Using
Return SearchCriteria
End Function
Thanks again!
To create a WHERE condition you need to provide (at the most basic level) three informations to the database engine. The first bit is the column name that you want to search for, the second piece is the operator that you want to use for matching records, and finally the value to search for
SELECT * FROM table WHERE FieldName = 'AStringValue'
Of course we could have a lot of variations with operators and field datatype but this answer is limited to your actual situation.
It is important to note that your query could return more than one record (in particular if you add wildcards operators as LIKE, so you cannot simply return a single value with this query, but instead you return a DataTable where you can loop over the Rows collection to see all the records returned by the query
So your code should be changed to
Private Function RetrieveObject(SearchCriteria As String) As DataTable
Dim myQuery = "SELECT * FROM Applicant WHERE [strFirstName] LIKE ?"
Try
Using cn = New OdbcConnection(myCon)
Using da = new OdbcDataAdapter(myQuery, cn)
da.SelectCommand.Parameters.Add("?", OdbcType.VarChar).Value = SearchCriteria
Dim dt = new DataTable()
da.Fill(dt)
return dt
End Using
End Using
Catch ex As Exception
MsgBox(ex.Message.ToString())
return Nothing
End Try
End Function
Now you could call this method with something like
Dim table = RetrieveObject("John%")
if table IsNot Nothing Then
For Each row in table.Rows
Console.WriteLine(row["strFirstName"].ToString())
Next
End If
If you really need to return a json string with all the FirstName matched then you could add this to the last lines of the code above
.....
da.Fill(dt)
Dim names = dt.AsEnumerable().Select(Function(x) x.Field(Of String)("strFirstName")).ToArray()
string output = JsonConvert.SerializeObject(names);
return output;
And of course change again the return value to be a string.
You can also pass your search criteria into function which returns dataset as shown below , one more thing ,you can use the function in textbox textchange event in forms
Also while search include LIKE as LIKE '%" & #strFirstName & "%' which can help you narrow search results if needed
Public Function Search(ByVal Criteria As String) As DataSet
Try
Dim ds As New DataSet
Using sqlCon As New SqlConnection(connStr)
stQuery="SELECT * FROM Applicant WHERE [strFirstName]
LIKE '%" & #strFirstName & "%'"
Dim sqlCmd As New SqlCommand(stQuery, sqlCon)
Dim sqlAda As New SqlDataAdapter(sqlCmd)
sqlCmd.CommandType = CommandType.Text
sqlCmd .Parameters.AddWithValue("#strFirstName", Criteria )
sqlAda.Fill(ds)
End Using
Return ds
Catch ex As Exception
MsgBox(ex.Message.ToString())
End Try
End Function