Ms-access "Great Than" or equal query - vb.net

I have an Ms-access DB that contain 40 students and I want to find students who are at least 18 years old.
I tried to use this code but it doesn't work!
Try
DataGridView1.Rows.Clear()
Dim dt As DataTable = New DBConnect().selectdata(String.Format("SELECT ID, Name FROM Students where Age > %{0}%", FlatTextBox8.Text))
For i As Integer = 0 To dt.Rows.Count - 1
DataGridView1.Rows.Add(i + 1, dt.Rows(i)(0), dt.Rows(i)(1))
Next
dt.Dispose()
dt = Nothing
Catch ex As Exception
End Try
How can I do this?

Name is a reserved word, so try with:
String.Format("SELECT ID, [Name] FROM Students where Age > {0}", FlatTextBox8.Text))
That said, use parameters.

It's better to use parametrized query in order to avoid sql injection.
This little function will fill and return a DataTable with the value you are looking at!
Private Function GetData() As System.Data.DataTable
Dim dt As New DataTable
Dim sqlCmd As String = "SELECT ID, Name FROM Students where Age > #Age"
Using myConnection As New SqlConnection(your_connection_string)
myConnection.Open()
Using myDataAdapter As New SqlDataAdapter(sqlCmd, myConnection)
myDataAdapter.SelectCommand.Parameters.Add("#Age", SqlDbType.Int) 'Change the type if your DB Table has another type
myDataAdapter.SelectCommand.Parameters("#Age").Value = Convert.ToInt16(FlatTextBox8.Text) 'Change the type if your DB Table has another type
myDataAdapter.Fill(dt)
End Using
myConnection.Close()
End Using
Return dt
End Function
Now it's time to call it inside your code:
Try
DataGridView1.Rows.Clear()
Dim dt As DataTable = GetData()
For i As Integer = 0 To dt.Rows.Count - 1
DataGridView1.Rows.Add(i + 1, dt.Rows(i)(0), dt.Rows(i)(1))
Next
dt.Dispose()
dt = Nothing
Catch ex As Exception
MsgBox(ex.Message)
Err.Clear
End Try
As you can notice, I also added a MsgBox() that will show you the error message if an exception is thrown. I found this very helpful while debugging.

Related

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

How to solve this: Conversion from type DBNull to type string is not valid

I think this is were I think the error is showing when I close the crystal report after creating a report.
Private Sub Populate(id As Integer, perdate As Date, controlnum As String, establishmentname As String, fname As String, mname As String, lname As String, address As String, pertype As String, ornum As String, amntpd As String, datepd As Date)
Dim row As String() = New String() {id, perdate, controlnum, establishmentname, fname, mname, lname, address, pertype, ornum, amntpd, datepd}
DataGridView1.Rows.Add(row)
End Sub
This is where the code for retrieving data from my database(MySql database) to datagrid view
Private Sub retrieve()
DataGridView1.Rows.Clear()
sql = "SELECT * FROM tblfsesmis"
Try
Using con
con.Open()
cmd = New MySqlCommand(sql, con)
adapter = New MySqlDataAdapter(cmd)
adapter.Fill(dt)
For Each row In dt.Rows
'It's in your Populate function that you want to check the DBNull values
Populate(row(0), row(1), row(2), row(3), row(4), row(5), row(6), row(7), row(8), row(9), row(10), row(11))
Next
dt.Rows.Clear()
DataGridView1.Refresh()
End Using 'con Object will be disposed automatically
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Can you help me in how to solve this? please ! thank you
If your application doesn't support null values for a field then modify your query so that null values cant appear.
So instead of: SELECT * FROM tblfsesmis
Use SELECT Id, PerDate, IsNull(ControlNum, '') .... FROM tblfsesmis.
IsNull will replace null values with a default that you have chosen.
Alternatively you can fix this in code with something like
Dim result = If(Convert.IsDBNull(val), "", val) on each field which could be null.
However as pointed out in the comment you don't appear to need these values to be cast to strings anyway. So just assign the datatable directly to the datasource.
Private Sub retrieve()
sql = "SELECT * FROM tblfsesmis"
Try
Using con
con.Open()
cmd = New MySqlCommand(sql, con)
adapter = New MySqlDataAdapter(cmd)
adapter.Fill(dt)
DataGridView1.DataSource = dt
End Using 'con Object will be disposed automatically
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Use DataRow.Field(Of T) extension method.
With DataRow.Field(Of String)(columnIndex) if value is DbNull then Nothing/null will be returned.
Populate(row.Field(Of Integer)(0), row.Field(Of String)(1))
If column of type Integer can be a NULL too, then use Nullable with GetValueOrDefault method
Populate(row.Field(Of Integer?)(0).GetValueOrDefault(), row.Field(Of String)(1))
But as #F0r3v3r-A-N00b suggested - you can use DataTable as datasource for DataGridView.
Private Sub retrieve()
Dim sql As String = "SELECT * FROM tblfsesmis"
Try
Using con As New MySqlConnection(yourConnectionString)
con.Open()
Using cmd As New MySqlCommand(sql, con)
Dim adapter As New MySqlDataAdapter(cmd)
Dim dt As New DataTable()
adapter.Fill(dt)
DataGridView1.DataSource = dt
End Using
End Using
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
In this way DataGridView will be updated automatically. Just check that DataGridView.AutoGenerateColumns = true(it is true by default)

Giving the value of a query to a variable

Help, I am using SQL Server as my database, and my back-end is VB.NET.
I want to assign the value of this query:
SELECT sum(productPrice) from cartTbl
to a variable, and then give the value to a textbox called totalPrice.
How do I perform this? Thank you in advance!
you can use
SELECT #var1=sum(productPrice) from cartTbl
Use an alias for your calculated column
SELECT sum(productPrice) as prod_sum
from cartTbl
Then you can read it like this
While dr.Read()
totalPrice.Text = dr("prod_sum")
End While
It is as simple as this, but please read some basic info on ADO.NET
Using con = new SqlConnection(.....constring here ....)
Using cmd = new SqlCommand("SELECT sum(productPrice) from cartTbl", con)
con.Open()
Dim result = cmd.ExecuteScalar()
Console.WriteLine(result)
End Using
End Using
You should use ExecuteScalar() if using ADO.NET
Public Function GetProductPrice() As Integer
Dim ProdPrice As Int32 = 0
Dim sql As String = "SELECT sum(productPrice) from cartTbl"
Using conn As New SqlConnection(connString)
Dim cmd As New SqlCommand(sql, conn)
Try
conn.Open()
ProdPrice = Convert.ToInt32(cmd.ExecuteScalar())
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Using
Return ProdPrice
End Function
You can then call this method to get the Price.
Dim prodPrice = GetProductPrice()
To expand on what has already been said, you could use the following to make it a little more flexable:
Private Sub Test()
'Get/set connection string
Me.TextBox1.Text = Me.SQLExecuteScalar(ConnectionString, "SELECT sum(productPrice) FROM cartTbl")
End Sub
Public Shared Function SQLExecuteScalar(ByVal ConnectionString As String, ByVal Query As String) As String
Dim Result As String = Nothing
Dim Exc As Exception = Nothing
Using Conn As New SqlClient.SqlConnection(ConnectionString)
Try
'Open the connection
Conn.Open()
'Create the SQLCommand
Using Cmd As New SqlClient.SqlCommand(Query, Conn)
'Create an Object to receive the result
Dim Obj As Object = Cmd.ExecuteScalar
If (Obj IsNot Nothing) AndAlso (Obj IsNot DBNull.Value) Then
'If Obj is not NULL
Result = Obj.ToString
End If
End Using
Catch ex As Exception
'Save error so we can (if needed) close the connection
Exc = ex
Finally
'Check if connection is closed
If Not Conn.State = ConnectionState.Closed Then
Conn.Close()
End If
End Try
End Using
'Check if any errors where found
If Exc IsNot Nothing Then
Throw Exc
End If
Return Result
End Function

get column value according to another column value from datatable in vb.net

i have a datatable similar to this:
id msg
1 thank you..
2 kindly...
3 please insert..
4 please stop
i need to get a msg according to a specific id from the datatable that's how i'm filling my datatable:
msgTable = selectMsg()
MsgBox(i need to get the msg here)
Public Function selectMsg() As DataTable
Dim command As SqlCommand = New SqlCommand("selectMsg", cn)
command.CommandType = CommandType.StoredProcedure
Dim da As New SqlDataAdapter(command)
'If dt.Rows.Count <> 0 Then
' dt.Rows.Clear()
'End If
Try
da.Fill(msgDS, "N_AI_HOME_CARE")
msgDT = msgDS.Tables(0)
Catch ex As Exception
logFile("SP selectMsg ---" + ex.Message)
End Try
Return msgDT
End Function
any suggestion will be much appreciated !
Supposing that your stored procedure returns the whole datatable of your messages (a very bad move because if the table is big you could have performance and network problems) then you need to apply the Select method with a filter expression to your returned datatable
msgTable = selectMsg()
Dim rows() = msgTable.Select("ID = " & idOfMessage)
if rows.Length > 0 then
MsgBox(row(0)(1).ToString()) ' read the first row, second column of the table'
End If
But I think you should use a more correct approach using a simple ExecuteScalar that doesn't return the entire datatable but just the first row and first column of a query
Public Function selectMsg(idOfMessage as Integer) As String
Dim command As SqlCommand = New SqlCommand("SELECT msg from tableName where ID = #id", cn)
command.Parameters.AddWithValue("#id", idOfMessage)
Dim result = command.ExecuteScalar()
if string.IsNullOrEmpty(result) Then
result = "No message found"
End If
return result
End Function
well acctually i just found that you use
MsgBox(msgTable.Rows(0)(1).ToString())
without any select method :)

Better way to print out rows from a datatable in vb.net

I am new to vb.net and I am trying to query a database and print out the records in the row to the console window. I got it to work, but I have a feeling that there is a more concise way to do this. One thing that I am sure is wrong is that I had to convert the dataset to a datatable to be able to retrieve the values. Is that correct? Could you take a look at the code below (especially the for loop) and let me know what I can improve upon?
Thanks!
Module Module1
Sub Main()
Dim constring As String = "Data Source=C:\Users\test\Desktop\MyDatabase1.sdf"
Dim conn As New SqlCeConnection(constring)
Dim cmd As New SqlCeCommand("SELECT * FROM ACCOUNT")
Dim adapter As New SqlCeDataAdapter
Dim ds As New DataSet()
Try
conn.Open()
cmd.Connection = conn
adapter.SelectCommand = cmd
adapter.Fill(ds, "testds")
cmd.Dispose()
adapter.Dispose()
conn.Close()
Dim dt As DataTable = ds.Tables.Item("testds")
Dim row As DataRow
Dim count As Integer = dt.Columns.Count()
For Each row In dt.Rows
Dim i As Integer = 0
While i <= count - 1
Console.Write(row(i))
i += 1
End While
Console.WriteLine(Environment.NewLine())
Next
Catch ex As Exception
Console.WriteLine("There was an error")
Console.WriteLine(ex)
End Try
Console.ReadLine()
End Sub
End Module
Here is how I would rewrite this for a few reasons:
1) You should always use Using statements with disposable objects to ensure they are correctly cleaned up. You had a good start with the dispose commands, but this way is safer.
2) It is more efficient to use ExecuteReader than loading everything into a dataset.
3) Your try/catch statement should include object creation as well as execution.
Finally, in response to your question about datasets and datatables, that code was absolutely correct: a dataset consists of zero or more datatables, so you were just extracting the existing datatable from the dataset.
Try
Dim constring As String = "Data Source=C:\Users\test\Desktop\MyDatabase1.sdf"
Using conn As New SqlCeConnection(constring)
conn.Open()
Using cmd As New SqlCeCommand("SELECT * FROM ACCOUNT", conn)
Dim reader As SqlCeDataReader
reader = cmd.ExecuteReader()
Do While reader.Read
For i As Integer = 0 To reader.FieldCount - 1
Console.Write(reader.GetString(i))
Next
Console.WriteLine(Environment.NewLine())
Loop
End Using
End Using
Catch ex As Exception
Console.WriteLine("There was an error")
Console.WriteLine(ex)
End Try
Console.ReadLine()
End Sub
One last note: since you are just printing to the console, it doesn't matter as much, but whenever you deal with a lot of strings, especially those that are to be concatenated, you should always consider using System.Text.StringBuilder.
Here is an example rewrite of the loop that prints to the console using stringbuilder (builds the string in memory, then dumps it to the console; I have also added the field name for good measure):
Dim sbOutput As New System.Text.StringBuilder(500)
For i As Integer = 0 To reader.FieldCount - 1
If sbOutput.Length <> 0 Then
sbOutput.Append("; ")
End If
sbOutput.Append(reader.GetName(i)).Append("=").Append(reader.GetString(i))
Next
sbOutput.AppendLine()
Console.Write(sbOutput.ToString)