I'm having trouble with code that loops through the tables that contain TRelationCode. When it finds one it has to get the RelationCode from it and then convert it into the new RelationCode and update it to the new one.
To create the new RelationCode I've made a function Called MakeRelationCode(OldRelation). I have this code to loop through the tables:
Dim query As String = "use fmsStage; SELECT * FROM INFORMATION_SCHEMA.columns WHERE COLUMN_NAME = 'TRelationcode'"
Dim myCmd As SqlDataAdapter = New SqlDataAdapter(query, con)
Dim myData As New DataSet()
myCmd.Fill(myData)
For Each table As DataTable In myData.Tables
For Each row As DataRow In table.Rows
For Each col As DataColumn In table.Columns
Next
Next
Next
But now I need to update the old codes to the new ones.
I prefer simple SQL commands and a little vb logic thus I skipped the SqlDataAdapter part. This will only cost performance and is only necessary if you display something in a grid and want two-way-binding.
The following code is untested and typed blind so please check for typos etc.
I put everything in one method.
Dim tableNames As New List(Of String)
'Key: Old code, Value: New code'
Dim trelationcodes As New Dictionary(Of String, String)
Using conn As New SqlClient.SqlConnection("YourConnectionString") 'Change connection string to your needs'
Dim qTableNames = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.columns WHERE COLUMN_NAME = 'TRelationcode'"
conn.Open()
'Get table names with TRelationcode column'
Using commTableNames As New SqlClient.SqlCommand(qTableNames, conn)
Dim dataReader = commTableNames.ExecuteReader()
While dataReader.Read()
tableNames.Add(dataReader.GetString(0))
End While
End Using
'Select all distinct old TRelationcode which will be updated'
Dim qTrelationcodesOld = "SELECT DISTINCT TRelationcode FROM {0}"
For Each tableName In tableNames
'Get all old TRelationcodes from table found previuosly'
Using commTrelationcodesOld As New SqlClient.SqlCommand()
commTrelationcodesOld.Connection = conn
commTrelationcodesOld.CommandText = String.Format(qTrelationcodesOld, tableName)
Dim dataReader = commTrelationcodesOld.ExecuteReader()
While dataReader.Read()
Dim code = dataReader.GetString(0)
If Not trelationcodes.ContainsKey(code) Then
trelationcodes.Add(code, "") 'Value will be set later'
End If
End While
End Using
'Get new TRelationcodes'
For Each tRelCodeOld In trelationcodes.Keys
trelationcodes(tRelCodeOld) = MakeRelationCode(tRelCodeOld)
Next
'Set new TRelationcodes'
Dim uTRelationcode = "UPDATE {0} SET TRelationcode = #newCode WHERE TRelationcode = #oldCode"
For Each tRelCodes In trelationcodes
Using commTrelationcodesNew As New SqlClient.SqlCommand()
commTrelationcodesNew.Connection = conn
commTrelationcodesNew.CommandText = String.Format(uTRelationcode, tableName)
commTrelationcodesNew.Parameters.Add("#oldCode", SqlDbType.VarChar).Value = tRelCodes.Key 'Varchar correct?'
commTrelationcodesNew.Parameters.Add("#newCode", SqlDbType.VarChar).Value = tRelCodes.Value 'Varchar correct?'
commTrelationcodesNew.ExecuteNonQuery()
End Using
Next
Next
End Using
The code is far away from being optimal, e.g. I skipped exception handling.
The most concerning part is your MakeRelationCode function. If the logic inside could be written in T-SQL in a Stored Procedure, the overall coding would also be simplified.
Related
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 would like to do a populate a column in my listbox for each field in my Access Database.
Right now I have to manually add the field:
QUERBOX.Columns.Add("Requestor Name", 200, HorizontalAlignment.Left)
How can I adapt my code below to automatically add columns each time I run the sub?
Dim queryString As String = "SELECT * FROM Table1;"
Dim connection As OleDbConnection
Dim command As OleDbCommand
Dim data_reader As OleDbDataReader
querbox.clear
connection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\apt.accdb")
connection.Open()
command = New OleDbCommand(queryString, connection)
data_reader = Command.ExecuteReader
If data_reader.HasRows Then
While data_reader.Read
Dim newitem As New ListViewItem()
newitem.Text = data_reader.GetValue(0) 'first column
newitem.SubItems.Add(data_reader.GetValue(1)) 'second column
QUERBOX.Items.Add(newitem)
End While
End If
As Plutonix suggested in comments, a DataGridView would probably be best suited, but for the sake of answering the question here's how I've done something similar:
connection.Open()
'' Fill a DataTable with all of the Column schema for the given table of 'Table1'
Dim schemaTable As DataTable = connection.GetSchema("Columns", New String() {Nothing, Nothing, "Table1", Nothing})
'' Iterate through each column in the Schema Table
For i = 0 To schemaTable.Rows.Count - 1 Step 1
'' Declare a new item for the list
Dim newItem As New ListViewItem()
newItem.Text = schemaTable.Rows(i)!COLUMN_NAME.ToString()
newItem.SubItems.Add(schemaTable.Rows(i)!COLUMN_NAME.ToString()
'' Add new item to the interface
QUERBOX.Items.Add(newItem)
Next
connection.Close()
This has helped me in projects where the user is familiar with the database structure and may need to select the fieldname as part of the business logic. For example, allowing someone with little database knowledge to standardize the records within a given field.
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.
I want to select a certain field from a datatable in VB based on the value of another field in the same row.
In SQL, it would easily be done by writing this query:
select error_message from table_errors where error_case="condition"
How do I do this if I have my SQL table filled in a datatable in VB?
How do I select the item("error_message") in the datatable based on the item("error_Case") field?
Any help would be appreciated
You can use Linq-To-DataSet:
Dim matchingRows As IEnumerable(Of DataRow) =
From row In table
Where row.Field(Of String)("error_case") = "condition"
If you just want one column (of course that works also in one step):
Dim errorMessages As IEnumerable(Of String) =
From row In matchingRows
Select row.Field(Of String)("error_message")
For Each error In errorMessages
Console.WriteLine(error)
Next
If you expect it to be just a single row use First or Single(throws an exception if there is more than one row):
Dim error As String = errorMessages.First()
Since First throws an exception if the sequence is empty you can use FirstOrDefault:
Dim error As String = errorMessages.FirstOrDefault() ' is null/Nothing in case of an empty sequence
All in one line (note that both Linq and DataTable.Select needs to use loops):
Dim ErrMessage As String = errorTable.AsEnumerable().
Where(Function(r) r.Field(Of String)("Error_Case") = TextCase.Text).
Select(Function(r) r.Field(Of String)("Error_Message")).
FirstOrDefault()
here is a worker version of the rough code
Dim connString As String = "select error_message from table_errors where error_case='condition'"
Dim conn As SqlClient.SqlConnection = New SqlClient.SqlConnection(connString)
conn.Open()
Dim cmd As SqlClient.SqlCommand = New SqlClient.SqlCommand(connString, conn)
Dim dTable As DataTable = New DataTable()
Dim dAdapter As SqlClient.SqlDataAdapter = New SqlClient.SqlDataAdapter(cmd)
dAdapter.Fill(dTable)
conn.Close()
Dim text As String
Dim dReader As DataTableReader = dTable.CreateDataReader()
While dReader.Read()
text = dReader.GetValue(0)
End While
dReader.Close()
I want to save a record in the database using a dataset, but my data is not committing into my database.
My code can be viewed below:
Dim mydataset1 As New MyDataSet
Dim row As DataRow = mydataset1.Tables("testtable").NewRow()
With row
.Item("name") = "Segun Omotayo"
.Item("address") = "Abuja"
End With
mydataset1.Tables("testtable").Rows.Add(row)
Any help will be appreciated
A DataSet/DataTable is a offline/in-memory representation of your database. If you want to update the database, you need to use a DataAdapter.
For example (assuming you're using MS-Sql-Server):
Public Function UpdateDataSet(dataSet As DataSet) As Int32
Using con = New SqlConnection(My.Settings.SqlConnection)
Dim sql = "INSERT INTO TUser(Name,Address)VALUES(#Name,#Address)"
Using cmd = New SqlCommand(sql, con)
cmd.Parameters.Add(New SqlParameter("#Name", SqlDbType.VarChar))
cmd.Parameters.Add(New SqlParameter("#Address", SqlDbType.VarChar))
Using da = New SqlDataAdapter()
da.InsertCommand = cmd
con.Open()
Dim rowCount = da.Update(dataSet)
Return rowCount
End Using
End Using
End Using
End Function
I could be rusty here since its a long time since I wrote any VB.NET or used data adapters/datasets/datatables but I think if you decide to take that route you would need code like this:
Dim connection As New SqlConnection("#####YourConnectionString#####")
connection.Open()
Dim adapter As New SqlDataAdapter("SELECT * FROM testtable", connection)
' For the line below to work, you must have a primary key field in "testtable"
Dim builder As New SqlCommandBuilder(adapter)
Dim testtable As New DataTable("testtable")
adapter.Fill(testtable)
Dim row As DataRow = testtable.NewRow()
With row
.Item("name") = "Segun Omotayo"
.Item("address") = "Abuja"
End With
testtable.Rows.Add(row)
adapter.Update(testtable)
connection.Close()