Find Row in Access DataTable - vb.net

I need to see if a row exists in a DataTable where a field in the table (plan_code) matches a variable (strPlanCode). If it finds a match, it then obtains the value from another field in that row; if not, it writes the row to an error list. The direction I started with was to set up a DataTable like this:
Using daProduct As New OleDbDataAdapter("SELECT * FROM [product]", con)
Dim cbProduct = New OleDbCommandBuilder(daProduct)
cbExtract.QuotePrefix = "["
cbExtract.QuoteSuffix = "]"
Dim dtProduct = New DataTable
daProduct.Fill(dtProduct)
But no methods from there seem to work and I'm wondering if I shouldn't have gone down the DataAdapter/DataTable path.
Some of the ones I've tried are:
strSearch = "plan_code = " & strPlanCode
intProdRow = dtProduct.Select(strSearch)
and
intProdRow = dtProduct.SelectCommand(strSearch)
But none of these get a result and/or will compile.
The old code, which used ODBC to connect to an SQL Anywhere DB, looks like this:
ls_command = "select * from product"
selectCMD = New OdbcCommand(ls_command, connectDB)
selectCMD.CommandTimeout = 30
productDA.SelectCommand = selectCMD
productDA.Fill(clp_valDS, "product")
porductTBL = clp_valDS.Tables("product")
productTBL.PrimaryKey = New DataColumn() {productTBL.Columns("plan_code")}
productDR = productTBL.Rows.Find(ls_plan_code)
If (productDR Is Nothing) Then
ls_error_message = "Plan Code " + ls_plan_code + " not found"
GoTo ErrorHandler
Else
ls_secondary_guar = productDR("secondary_guar")
End If

I would use the following approach:
For Each row As System.Data.DataRow In dtProduct.Rows
if not row.item("plan_code") is DBNull.Value then
If row.Item("plan_code").ToString = strPlanCode Then
'do what you want with the matching row.
End If
end if
Next

Related

Filter and sort datagridview

I have created an item list in which all items are loaded, and I need to filter the data according to the text entered in the textbox.
Please guide me how to filter and sort data, I have created the fallowing code
Private Sub loadsearchitems(item As String)
dgvsearchitem.ScrollBars = ScrollBars.Vertical
On Error Resume Next
con = New System.Data.OleDb.OleDbConnection(connectionString)
con.Open()
Dim ds As DataSet = New DataSet
Dim adapter As New OleDb.OleDbDataAdapter
sqlstr = "SELECT Imaster.icode, Imaster.iname & ' ' & MfgComTab.comname as[Iname], Imaster.unitcode, Imaster.tax,Unit.unitname FROM ((Imaster INNER JOIN MfgComTab ON Imaster.mccode = MfgComTab.mccode) INNER JOIN Unit ON Imaster.unitcode = Unit.unitcode) WHERE (Imaster.isdeleted = 'N') AND Imaster.comcode=#comcode AND Imaster.iname like '%' & #item & '%' order by iname asc "
adapter.SelectCommand = New OleDb.OleDbCommand(sqlstr, con)
adapter.SelectCommand.Parameters.AddWithValue("#comcode", compcode)
adapter.SelectCommand.Parameters.AddWithValue("#iname", item)
adapter.Fill(ds)
If ds.Tables(0).Rows.Count > 0 Then
dgvsearchitem.DataSource = ds.Tables(0)
dgvsearchitem.Columns("unitname").Visible = False
dgvsearchitem.Columns("unitcode").Visible = False
dgvsearchitem.Columns("icode").Visible = False
dgvsearchitem.Columns("tax").Visible = False
dgvsearchitem.Columns("Iname").Width = 371
Else
ds.Dispose()
End If
con.Close()
End Sub
But in the above code the application is slow because every time any text is entered a query is executed. Please tell me any solution where query is executed only once and when we enter the text it only search the items by wild card and filter it.
If you initially set the DataGridView with all the records, then you could avoid to go again to the database to extract your data in a filtered way. You have already extracted everything, so you could simply set the DataSource with a DataView filtered locally
' Code that loads initially the grid
sqlstr = "SELECT Imaster.icode, Imaster.iname .....FROM ...." ' NO WHERE HERE
....
dgvsearchitem.DataSource = ds.Tables(0).DefaultView
Now in your loadsearchitems instead of executing again a query against the database you could take the datasource and set the RowFilter property
Dim v as DataView = CType(dgvsearchitem.DataSource, DataView)
v.RowFilter = "Imaster.comcode='" & compcode & "' AND Imaster.iname like '%" & item & "'%'"
Note how the RowFilter property doesn't understand the use of parameters, so if it is possible for your comcode field to contain single quotes you need to add a some form of doubling the quotes (a String.Replace will do) to avoid a syntax error. And yes, there is no worry for Sql Injection on a DataView (it is a disconnected object and whatever your user types in the compcode field it cannot reach the database)

Update SQL Database Table Using a TableAdapter with SqlCommandBuilder and a Worksheet exported to a DataTable

I am exporting data from a spreadsheet worksheet range into a datatable (dtpHExportDataTable). When I call ShowResult(dtpHExportDataTable), the grid form displays the correct datatable information (headers and rows of data). Likewise, when I call ShowResult(resultsDataTable) the grid form displays the correct datatable information (the database table rows including the updated rows)
Using cnSQL1 As New SqlConnection
cnSQL1.ConnectionString = cnString
Using adapter1 = New SqlDataAdapter("SELECT SampleNo, Results, Complete_Date, Dex_Row_Id " _
& "FROM LIMS.dbo.Analytical_Sample_Log_ResultsInfo", cnSQL1)
Dim builder1 As New SqlCommandBuilder(adapter1)
adapter1.UpdateCommand = builder1.GetUpdateCommand()
Using New SqlCommandBuilder(adapter1)
adapter1.Fill(resultsDataTable)
resultsDataTable.PrimaryKey = New DataColumn() {resultsDataTable.Columns("Dex_Row_Id")}
dtpHExportDataTable = resultsDataTable.Clone()
‘not sure if needed, just trying to make sure datatypes are correct
dtpHExportDataTable.Columns("SampleNo").DataType = System.Type.GetType("System.Int32")
dtpHExportDataTable.Columns("Results").DataType = System.Type.GetType("System.String")
dtpHExportDataTable.Columns("Complete_Date").DataType = System.Type.GetType("System.DateTime")
dtpHExportDataTable.Columns("Dex_Row_Id").DataType = System.Type.GetType("System.Int32")
' Create the exporter that obtains data from the specified range,
' skips header row if required and populates the specified data table.
Dim exporter As DataTableExporter = workSheet.CreateDataTableExporter(range, dtpHExportDataTable, rangeHasHeaders)
AddHandler exporter.CellValueConversionError, AddressOf exporter_CellValueConversionError
' Specify exporter options.
exporter.Options.ConvertEmptyCells = True
exporter.Options.DefaultCellValueToColumnTypeConverter.EmptyCellValue = 0
' Perform the export.
exporter.Export()
ShowResult(dtpHExportDataTable) ‘grid form shows expected information
For index = 1 To dtpHExportDataTable.Rows.Count - 1
dtpHExportDataTable.Rows(index).SetModified()
Next
resultsDataTable.Merge(dtpHExportDataTable)
ShowResult(resultsDataTable) ‘grid form shows expected information
Try
adapter1.Update(resultsDataTable)
Catch ex As Exception
MsgBox("Update failed")
End Try
End Using
End Using
End Using
My tableadapter Query Builder, Update command text is “UPDATE Analytical_Sample_Log_ResultsInfo
SET SampleNo = #SampleNo, Results = #Results, Complete_Date = #Complete_Date
WHERE (Dex_Row_Id = #Original_Dex_Row_Id)
In essence, the datatables populate correctly; however, the tableadapter is not updating the sql database table even though an exception is not thrown.
This is my final code, and it works for me. Note the change in which datatable is being modified, the revised location of SetModified, and the addition of the updateStatement since I am updating only 4 of the 11 columns in the database table.
Using adapter1 = New SqlDataAdapter("SELECT SampleNo, Results, Complete_Date, Dex_Row_Id " _
& "FROM LIMS.dbo.Analytical_Sample_Log_ResultsInfo", cnSQL1)
Dim builder1 As New SqlCommandBuilder(adapter1)
adapter1.UpdateCommand = builder1.GetUpdateCommand()
Using New SqlCommandBuilder(adapter1)
adapter1.Fill(resultsDataTable)
resultsDataTable.PrimaryKey = New DataColumn() {resultsDataTable.Columns("Dex_Row_Id")}
dtpHExportDataTable = resultsDataTable.Clone()
Dim exporter As DataTableExporter = workSheet.CreateDataTableExporter(range, dtpHExportDataTable, rangeHasHeaders)
AddHandler exporter.CellValueConversionError, AddressOf exporter_CellValueConversionError
exporter.Options.ConvertEmptyCells = True
exporter.Options.DefaultCellValueToColumnTypeConverter.EmptyCellValue = 0
exporter.Export()
For index = 1 To resultsDataTable.Rows.Count - 1
resultsDataTable.Rows(index).SetModified()
Next
resultsDataTable.Merge(dtpHExportDataTable)
Dim updateStatement As String = "UPDATE LIMS.dbo.Analytical_Sample_Log_ResultsInfo SET [SampleNo] = #SampleNo, [Results] = #Results, [Complete_Date] = #Complete_Date " _
& "WHERE [Dex_Row_Id] = #Dex_Row_Id"
Dim updateCommand As New SqlCommand(updateStatement, cnSQL1)
updateCommand.Parameters.Add("#SampleNo", SqlDbType.Int, 0, "SampleNo")
updateCommand.Parameters.Add("#Results", SqlDbType.NChar, 10, "Results")
updateCommand.Parameters.Add("#Complete_Date", SqlDbType.Date, 10, "Complete_Date")
updateCommand.Parameters.Add("#Dex_Row_Id", SqlDbType.Int, 0, "Dex_Row_Id")
adapter1.UpdateCommand = updateCommand
adapter1.Update(resultsDataTable)
End Using
End Using

Loop SQL if has Rows then continue

I am trying to run this loop to run if the results continue to have rows. So basically if my sql statement continues to return a row on ssql = "SELECT TOP 1 * from [OrderHeader] Where ([IsisDownloadDate] is null or [IsisDownloadDate] = '')"
then run submit to webrequest, then return a value, then submit that value to the same row and update that column
So basically I just want it to keep updating the next row as long as ssql keeps returning rows, and if it does not return any rows then stop.
I got everything to work, besides the continuous looping issue
Here is the code:
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
Dim objDR As SqlClient.SqlDataReader
Dim objCommand As SqlClient.SqlCommand
Dim ConnectionString As String = "Data Source=localhost;Initial Catalog=datarep;user id=sa;password=test123;"
Dim objConnection As SqlClient.SqlConnection
Dim ssql As String
objConnection = New SqlClient.SqlConnection(ConnectionString)
ssql = "SELECT TOP 1 * from [OrderHeader] Where ([IsisDownloadDate] is null or [IsisDownloadDate] = '')"
If objConnection.State <> ConnectionState.Open Then
objConnection.Open()
End If
objCommand = New SqlClient.SqlCommand(ssql, objConnection)
objDR = objCommand.ExecuteReader(CommandBehavior.CloseConnection)
objCommand = Nothing
If objDR.HasRows Then
While objDR.Read()
Dim objSO As New WebReference.SalesOrder
Dim objBTAddr As New WebReference.BillToAddress
Dim objSTaddr As New WebReference.ShipToAddress
Dim objAddr As New WebReference.Address
Dim objPart() As WebReference.SalesOrderPart
Dim objMisc As New WebReference.SalesOrderMiscCharges
Dim objPayment As New WebReference.Payment
Dim objCreditCard As New WebReference.SalesOrderCreditCard
Dim objApproval As New WebReference.SalesOrderCreditCardApproval
objSO.OrderNumber = "69355522"
objSO.CompanyId = "301"
objSO.CustomerNumber = "5838303"
objSO.Code = "I"
objSO.PONumber = objDR("OrderNumber").ToString()
objSO.Source = "TAW.COM"
objSO.OrderDate = Format(Date.Now, "MM/dd/yy")
objSO.RequiredDate = Format(Date.Now, "MM/dd/yy")
objSO.ShipCode = "UPG"
objSO.EmployeeId = "1"
objAddr.Name = "José Peña,EPS H-1607"
objAddr.Address1 = "LÄRKGATAN 9"
objAddr.City = "Québec"
objAddr.Country = "US"
objAddr.State = "CA"
objAddr.Zip = "90220"
objSTaddr.Address = objAddr
'objSTaddr.Phone = "310-900-5509"
objBTAddr.AccountNumber = "595522"
objBTAddr.Address = objAddr
objSO.BillToAddress = objBTAddr
'turn on for .88
'objSO.ShipTo = objSTaddr
'objSO.ShipTo.Phone = objSTaddr.Phone
ReDim objPart(1)
objPart(0) = New WebReference.SalesOrderPart
objPart(0).PartNumber = "EVE510-621"
objPart(0).PartId = "EVE"
objPart(0).Quantity = 1
objPart(0).Price = 39.99
objPart(0).Description = "PWRAID SPCR"
objSO.Parts = objPart
Dim ws As New WebReference.WebServiceTyped
Dim result As WebReference.SubmitOrder = ws.SubmitSalesOrder(objSO)
Dim ordernum As String = result.OrderId
Dim s As String = "Data Source=localhost;Initial Catalog=datarep;user id=sa;password=test123;"
Dim sql As String
Dim con As New SqlConnection
con = New SqlConnection(s)
con.Open()
sql = "WITH UpdateList_view AS ( SELECT TOP 1 * from [OrderHeader] Where ([IsisDownloadDate] is null or [IsisDownloadDate] = '') ) update UpdateList_view set [IsisDownloadDate] = '" & result.OrderId & "'"
Dim cmd As New SqlClient.SqlCommand(sql, con)
cmd.ExecuteNonQuery()
con.Close()
End While
End If
objDR.Close()
objDR = Nothing
End Sub
Besides the whole, why would you want to do it this way issue, the problem is that you are only selecting one row. Your while loop goes through that singular row then exits. There are a lot of issues with this code though and I would recommend that you do not do it this way.
Let's go through the code a little bit. Let's say there are two rows that fit this criteria, row J and row 6. You select top 1 and you get row J back. Your If objDR.HasRows will evaluate to true and you will go into the while condition. After you read and update, you go back to the while condition. You already read row J and your vb.net code is not aware of what else is in the database, so we exit the while loop and exit the sub.
I recommend selecting all the rows that fit your criteria right off the bat. Selecting all of your data instead of top 1 will be better than selecting what you want one row at a time from the database because it is expensive to go out and connect to the database. Your way, you will be connecting to the database twice for each row that fits the criteria. My way, you will connect once for each row plus one more time at the beginning. If you are updating a lot of rows this will be a huge difference. Your sql should look more like
SELECT UniqueId from [OrderHeader] Where ([IsisDownloadDate] is null or [IsisDownloadDate] = '')
Now when you loop, you are going through all of the data. I also recommend that when you update the data make sure you use a parameter that will update the specific row you are looking at, some sort of unique id is usually best. In reality, you don't need a cte for this either. Something like:
sql = New SqlCommand("UPDATE UpdateList_view SET [IsisDownloadDate] = #OrderId WHERE UniqueId = #ID", dbConn)
sql.Parameters.AddWithValue("#OrderId", result.OrderId)
sql.Parameters.AddWithValue("#Id", objDR.GetInt32(0))
Note, objDR.GetInt32(0) would be setting the #Id parameter to the unique id that would be selected in the first sql query. Also, please please look at how I have added parameters to the sqlCommand. You should get into the habit of coding this way because update UpdateList_view set [IsisDownloadDate] = '" & result.OrderId & "'" leaves you open to sql injection.
Lastly, you may want to consider doing a sql bulk update rather than updating each row one at a time. This is probably a good place to start.

VB.Net Select-Like query in MS Access not working

I need to show the data from the column 'Purchaser' starting with the text entered in the textbox 'Purchaser' on the form. I am using MS Access 2003 database.
For this I am using the following...
Dim query = "SELECT * FROM Details WHERE [Purchaser] LIKE '" & Purchaser.Text & "*'"
Dim dc = New OleDbCommand(query, cn)
Dim rows = dc.ExecuteNonQuery
cn.Close()
If rows = 0 Then
'Show a form for new entry
Else
Dim oleadap = New OleDbDataAdapter(query, cn)
Dim dset As DataSet = Nothing
oleadap.Fill(dset, "Details")
For i = 0 To rows
Dim purName = dset.Tables("Details").Rows(i).Item("Purchaser").ToString
Dim purAddr = dset.Tables("Details").Rows(i).Item("Address").ToString
'Populate a list
Next
End If
The variable 'rows' always turns out to be zero even if I check for a Purchaser starting with, say A, in the database.
That should be:
Dim query = "SELECT * FROM Details WHERE [Purchaser] LIKE '" _
& Purchaser.Text & "%'"
In MS Access, the wild card is asterisk (*), outside of it, the wildcard is percent (%)
In addition, you have ExecuteNonQuery, but that is not true. You are executing a query, here are a few notes for testing.
Dim query = "SELECT * FROM Details WHERE [Purchaser] LIKE '" _
& Purchaser.Text & "%'"
Dim dc = New OleDbCommand(query, cn)
Dim rows As OleDb.OleDbDataReader
rows = dc.ExecuteReader
If rows.HasRows Then
Do While rows.Read()
Console.WriteLine(rows("Purchaser"))
Loop
End If
Console.ReadLine()
Can you use % instead of *. And another one, use parameter.
Dim query = "SELECT * FROM Details WHERE [Purchaser] LIKE #purc & '%' "
Dim dc = New OleDbCommand(query, cn)
dc.Parameters.AddWithValue("#purc", Purchaser.Text)
Dim rows = dc.ExecuteNonQuery

VB.NET - "There is no row at position 0" but Records in Database

Having a DataSet problem in VB.NET/Access.
Code should return 1 record and display the results on a form.
Basically when I step through the code in debug mode it returns 1 row and works fine,
but when I run the code without breakpoints I get the error message:
There is no row at position 0
VB.NET 2010 & MS Access 97
Dim sConnectionString As String = "dsn=MyDatabase"
Dim sSQL As String = ""
Dim DBConnection As New OdbcConnection(sConnectionString)
Dim dsMaster As New DataSet
Dim daMaster As New OdbcDataAdapter
Dim dtMaster As New DataTable
Try
DBConnection.Open()
sSQL = "SELECT * FROM myTable"
daMaster.SelectCommand = New OdbcCommand(sSQL, DBConnection)
daMaster.Fill(dsMaster, "MasterDataSet")
If dsMaster.Tables(0).Rows.Count <> 0 Then
dtMaster = dsMaster.Tables(0)
sItem1 = dtMaster.Rows(0).Item(0).ToString
sItem2 = dtMaster.Rows(0).Item(1).ToString
sItem3 = dtMaster.Rows(0).Item(2).ToString
Else
MessageBox.Show("No Records Available", "Error", MessageBoxButtons.OK)
End If
When I run the code, I get the messagebox saying No Records.
When I run in debug mode with a breakpoint on the IF statement, I get the messagebox saying No Records.
When I run in debug mode with a breakpoint on the FILL statement, I get 1 record returned and the code in IF statement executes.
Any ideas?
Here's how I would do it:
Dim sConnectionString As String = "dsn=MyDatabase"
Dim sSQL As String = ""
Dim DBConnection As New OdbcConnection(sConnectionString)
Dim dsMaster As New DataSet
Dim daMaster As New OdbcDataAdapter
Dim dtMaster As New DataTable
Try
DBConnection.Open()
sSQL = "SELECT * FROM myTable"
daMaster.SelectCommand = New OdbcCommand(sSQL, DBConnection)
daMaster.Fill(dsMaster)
If dsMaster.Tables(0).Rows.Count <> 0 Then
dtMaster = dsMaster.Tables(0)
sItem1 = dtMaster.Rows(0).Item(0).ToString
sItem2 = dtMaster.Rows(0).Item(1).ToString
sItem3 = dtMaster.Rows(0).Item(2).ToString
Else
MessageBox.Show("No Records Available", "Error", MessageBoxButtons.OK)
End If
I removed the "MasterDataSet" parameter value from daMaster.Fill() because adding it would leave dsMaster.Tables(0) empty and put all your query data in dsMaster.Tables("MasterDataSet").
Looks like this is most likely where your error was coming from.
Also you don't really need dtMaster because the data is already in a DataTable (dsMaster.Tables(0)) when you fill it.
So you would just reference those columns the same way:
sItem1 = dsMaster.Tables(0).Rows(0)(0).ToString
Keep in mind that providing the column names make it easier to read the code. So if you have the following query:
Dim sSQL As String = "SELECT Username, UserMail FROM Users WHERE UserID = 3"
Getting that data would look like this:
sItem1 = dsMaster.Tables(0).Rows(0)("Username")
You don't specifically need the .ToString added there, but if you don't get the data you expect, then add it in rather.