I'm wondering on whether its possible to check if a specific cell in a record is empty before attempting to collect its value and crashing the program if it cant be assigned to a variable.
Something along the lines of SELECT FirstNameColumn FROM tableNames WHERE LastNameColumn = "Smith", and to test if the FirstNameColumn has a value in it.
Im using VB.net, with the OleDB and an Access Database.
If you had some code that retrieved a record, and some of the values on the row might be null:
Public Sub ReadMyData(ByVal connectionString As String)
Dim queryString As String = "SELECT FirstNameColumn FROM tableNames WHERE LastNameColumn = 'Smith'"
Using connection As New OleDbConnection(connectionString)
Dim command As New OleDbCommand(queryString, connection)
connection.Open()
Dim reader As OleDbDataReader = command.ExecuteReader()
While reader.Read()
If Not reader.IsDbNull(0) Then
Console.WriteLine(reader.GetString(0))
End If
End While
reader.Close()
End Using
End Sub
A DataReader has an IsDBNull method hat will tell you whether a cell on a row is null.
Really though, using a DataReader is really low level and quite hard work. There are a lot easier ways to use a database. The next step up might reasonably be a dataadapter and datatable, offering a similar function:
Dim da as New OleDbDataAdapter("SELECT FirstNameColumn FROM tableNames WHERE LastNameColumn = 'Smith'", connStr)
DataTable dt = new DataTable()
custDA.Fill(dt)
For Each ro as DataRow in dt.Rows
If Not ro.IsNull("FirstNameColumn") Then
Console.WriteLine(ro("FirstNameColumn"))
End If
Next ro
TableAdapters another level of abstraction, removes all the horrible dealing with string column names amongst other things:
Dim ta as New PersonTableAdapter
Dim dt as PersonDataTable = ta.GetData()
For Each ro in dt
If Not ro.IsFirstNameColumnNull() Then
Console.WriteLine(ro.FirstNameColumn)
End If
Next ro
Entity Framework is probably equivalently high level, possibly higher:
Dim p as Person = context.Person.Where(Function(x) x.LastName = "Smith")
If p.FirstNameColumn Is Not Nothing Then
Console.WriteLine(p.FirstNameColumn)
End If
Related
I have a SQL database with fields [ServiceDate],[CLID], [Reading], [DueAmt], [PaidAmt], [Balance] and [Status]. The idea is to choose accounts which have not been paid for the last 4 months and output the result to Listivew control using VB.Net (VS18 IDE). I need help with an example or reference on how to write this query from within Visual Studio IDE using VB.Net.
Most of other platforms I visited do not supply sufficient explanatory notes and codes to get what I'm supposed to do and learn from it. Also, I want the column for ServiceDate in the Listview contro to be formatted as short date, DueAmt, PaidAmt and Balance to Currency.
I will appreciate any help
Thank you.
I assumed SQL Server, [ServiceDate] as a DataTime in the database and [Balance] as some sort of number in the database.
Private Function GetOldAccounts() As DataTable
Dim dt As New DataTable
Using cn As New SqlConnection("Your connection string")
Using cmd As New SqlCommand("Select * From YourTable Where [ServiceDate] < #d AND [Balance] > 0")
cmd.Parameters.Add("#d", SqlDbType.DateTime).Value = DateTime.Now.AddMonths(-4)
cn.Open()
Using dr As SqlDataReader = cmd.ExecuteReader
If dr.HasRows Then
dt.Load(dr)
Else
Return Nothing
End If
End Using
End Using
End Using
Return dt
End Function
I thought you would be able to find how to fill a ListView from a DataTable.
ListViews display a text property which is a string. If you need typed columns then look at the DataGridView which can be easily bound to a DataTable.
Private Sub FillListView()
Dim dt As DataTable = GetOldAccounts()
lv.Items.Clear()
Dim lstAccounts As New List(Of ListViewItem)
lv.BeginUpdate() 'keeps the control from repaintinng on every iteration
For Each r As DataRow In dt.Rows
Dim li As New ListViewItem()
li.Text = CDate(r("ServiceDate")).ToShortDateString
li.SubItems.Add(r("CLID").ToString)
li.SubItems.Add(r("Reading").ToString)
li.SubItems.Add(r("DueAmt").ToString)
li.SubItems.Add(CDec(r("PaidAmt")).ToString("N2"))
li.SubItems.Add(CDec(r("Balance")).ToString("C")) 'Will include the $
li.SubItems.Add(r("Status").ToString)
Dim i As Integer
Dim s As String = i.ToString("C")
lstAccounts.Add(li)
Next
lv.BeginUpdate() 'keeps the control from repaintinng on every addition
lv.Items.AddRange(lstAccounts.ToArray)
lv.EndUpdate()
End Sub
So I have a MS Access Database with 1 table (Records) and 2 fields in it ("RecordID" (Number), which is the primary key, and "LowRes" (OLE Object) which is a low Resolution image). There are about 100 records.
I/m trying to load the Access Table into a DataTable (ID_Table) in VB.net.
Code so far:
Dim cnString As String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=SBS2257_ID.accdb;"
Dim theQuery As String = "SELECT [RecordID], [LowRes] FROM [Records];"
Using CN As New OleDbConnection(cnString)
Dim command As New OleDbCommand(theQuery, CN)
Using objDataAdapter = New OleDbDataAdapter(command)
Dim ID_Table As New DataTable
CN.Open()
Dim pictureData As Byte() = DirectCast(command.ExecuteScalar(), Byte())
Dim picture As Image = Nothing
Using stream As New IO.MemoryStream(pictureData)
picture = Image.FromStream(stream)
objDataAdapter.Fill(ID_Table)
End Using
End Using
End Using
However the "DirectCast" command fails when I tell it to look at more then 1 field in my SQL statement with a datatype mismatch (if I just do [LowRes] it does not throw a error). However, I get stuck again when trying to apply the result to the table via the objDataAdapter, it doesnt fill the table with anything? I also notice that "picture" only contains the first image in the database.
I could put this database query in a function using "WHERE RECORDID=..." and loop it manually building the table returning "picture" each time, but Id like to avoid running a function 100 times, esp one that access a database.
Is it possible to read the whole database that contains images and just load it directly into a Datatable in one big swoop?
EDIT: So I got this to work:
Dim strConnection As String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=SBS2257_ID.accdb;"
Dim strSQL As String = "SELECT [RecordID], [LowRes] FROM [Records];"
Using objConnection = New OleDbConnection(strConnection)
Using objCommand = New OleDbCommand(strSQL, objConnection)
Using objDataAdapter = New OleDbDataAdapter(objCommand)
Dim objDataTable As New DataTable("IDs")
objDataAdapter.Fill(objDataTable)
Return objDataTable
End Using
End Using
End Using
how ever when I go to view row 0, col 1 which should be the first LowRes image via a .ToString Useing this code:
Private Sub PrintValues(ByVal table As DataTable)
For Each row As DataRow In table.Rows
For Each col As DataColumn In table.Columns
MsgBox(row(col).ToString())
Next col
Next row
End Sub
It just displays "System.Byte[]". It knows its a Byte datatype, but how do I display that in a picturebox?
The ExecuteScalar() executes the query, and returns the first column of the first row in the result set returned by the query.
as your query is
Dim theQuery As String = "SELECT [RecordID], [LowRes] FROM [Records];"
the first column is RecordID which is not a Byte().
you can change your query as following:
Dim theQuery As String = "SELECT [LowRes] FROM [Records];"
or you have to use other methods to get data from the database
Dim strSql As String = "SELECT [RecordID], [LowRes] FROM [Records]"
Dim dtb As New DataTable
Using cnn As New OleDbConnection(connectionString)
cnn.Open()
Using dad As New OleDbDataAdapter(strSql, cnn)
dad.Fill(dtb)
End Using
cnn.Close()
End Using
I want to know which is the best way to store database value in vb.net, For example, I've this code:
Dim conn As MySqlConnection = Connection() 'Return a connection obj
conn.Open()
Dim transaction = conn.BeginTransaction
Dim cmd = New MySqlCommand("SELECT * FROM tb ORDER BY ID")
Dim ResultSet = Cmd.ExecuteReader
If ResultSet.HasRows Then
Do While ResultSet.Read
'Here the value should be store
Loop
End if
How you can see I take all table from my database, now I want store each records in a structure that allow me to access it like the table. An array is good for do this? A list? Which is the best way?
There is no best way. You have different options. For example:
As an option you can use a DataTable
Also you can store values in a generic List(Of T).
If you prefer working with DataTable it will be more simple to use DataAdapter to fill the DataTable. This way you can also create your List(Of T) from your DataTable.
Example of Using DataDapter to fill DataTable
Dim Connection = "Connection String"
Dim Command = "SELECT * FROM Category"
Dim Adapter = New SqlDataAdapter(Command, Connection)
Dim Table = New DataTable()
Adapter.Fill(Table)
This way the DataTable will have columns with name of columns in your result set.
Also you can fill your data in a List(Of T) using the DataTable this way:
Dim ListOfCategory = Table.Rows.Cast(Of DataRow) _
.Select(Function(Row)
Return New Category With
{
.Id = Row.Field(Of Integer)("Id"),
.Name = Row.Field(Of String)("Name")
}
End Function).ToList()
Note
If can change the way you are writing your application, you can use Entity Framework as a good option to work with data.
I have 2 data sources from different source types, like:
Dim connSql As String = "Data Source=sql_src;Initial Catalog=my_db;Persist Security Info=True;User ID=usr;Password=pwd;"
Dim connOle As String = "Provider=IBMDA400;Data source=src;User Id=usr;Password=pwd"
dim qrySql as String = "Select uniqueID, name From tblSql"
dim qryOle as String = "Select name, ID From tblOle"
I place them into DataTables using functions like this (mostly for reference):
Public Shared Function sqlQryDT(qry As String, conn As String) As DataTable
Dim dt As New DataTable
Dim sqlconn As New SqlClient.SqlConnection(conn)
sqlconn.Open()
Dim adapter As New SqlClient.SqlDataAdapter(qry, sqlconn)
Try
adapter.Fill(dt)
Catch ex As Exception
Finally
sqlconn.Close()
End Try
Return dt
End Function
Public Shared Function oleQryDT(qry As String, conn As String) As DataTable
Dim dt As New DataTable
Dim cn As New OleDb.OleDbConnection(conn)
Dim cmd As New OleDb.OleDbCommand("", cn)
Dim da As New OleDb.OleDbDataAdapter(cmd)
cmd.CommandText = qry
Try
cn.Open()
da.Fill(dt)
Catch ex As Exception
Finally
cn.Close()
End Try
Return dt
End Function
Dim dtSql as DataTable = sqlQryDT(qrySql, connSQL)
Dim dtOle as DataTable = oleQryDT(qryOle , connOle)
My goal is to have a DataTable consisting of uniqueID,name,ID
(Edit) If I could do an SQL query it would look like SELECT * FROM dtSql JOIN dtOle ON dtSql.name = dtOle.name
I have tried using a DataRelation by placing the tables into a DataSet and adding a relationship on name, but since names may not be unique, this fails.
I have also tried using LINQ, but that always returns IEnumerable(System.Collections.Generic) and I can't find an easy way to place the contents into a DataTable, except by iterating through every item. And, the code is messy when there are a large number of columns.
I feel like there should be a way to do this without using a For Each loop
I looked at these question, but they didn't fully help me.
How to inner join two already filled DataTables in VB.NET
Merging 2 data tables in vb.net
I'm trying (using SQL and VB.Net) to get a list of dates and strings (representing a film name) using a SELECT command, and then look through each of the 'dates' in the list, one after the other. Like a 'FOR EACH' loop.
I'm not entirely sure how to do this, but here's what I have so far:
Dim Con = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;DataSource=ApplicationData.accdb;Persist Security Info=False;")
Con.Open() 'Open the connection
Dim Cmd As New OleDbCommand("SELECT fDateAdded, fName FROM Films", Con)
Cmd.CommandType = CommandType.Text
Dim Rdr As OleDbDataReader = Cmd.ExecuteReader()
Dim schemaTable As DataTable = Rdr.GetSchemaTable()
Dim row As DataRow
Dim column As DataColumn
For Each row In schemaTable.Rows
For Each column In schemaTable.Columns
' WHAT TO DO HERE?
Next
Next
How can I go about achieving my goal?
Your for-next loop should be something like this...
For Each row As DataRow In dtDataTable.Rows
If row.Item("fDateAdded") = *your match criteria* Then
*Do something - you can utilies* row.Item("fName") *if you need*
End if
Next row
The match criteria can of course be anything < <= > >= or a combination to give you a range etc.
Hope that helps.