Loop SQL if has Rows then continue - sql

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.

Related

Looping through tables and querying each one which has TRelationcode in it

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.

out of range error in vb.net and access get maxnumber

iam trying to get the max number from table and insert it to another number
with vb.net 2008 and access db 2003 this my code
Dim strQ As String = "SELECT MAX(IDbatch) from batches "
Dim IDbatch As Integer
Dim cmdQ As OleDbCommand = New OleDbCommand(strQ, con)
If Not con.State = ConnectionState.Open Then
con.Open()
End If
Dim QReader As OleDbDataReader
Dim it As Integer
QReader = cmdQ.ExecuteReader
If QReader.FieldCount > 0 Then
While QReader.Read
it = QReader.Item("IDbatch")
MsgBox(it)
End While
End If
I am getting Out of range error
Change your query to
Dim strQ As String = "SELECT MAX(IDbatch) as MaxIDbatch from batches "
and your code that read the value to
it = QReader.Item("MaxIDbatch")
As you have it now the MAX(IDbatch) creates a field with a different name than IDbatch and trying to retrieve the content of that field using the name IDbatch fails giving the Index out of range exception
By the way, your check for FieldCount > 0 will be always true also in cases where there is no record in the batches table. So, if you have done that to protect in case of no record, then it is better to write
Dim result = cmdQ.ExecuteScalar()
if result IsNot Nothing then
Dim it = Convert.ToInt32(result)
MsgBox(it)
End If
And with this approach you could also leave out the aliasing on the IDbatch field

Find Row in Access DataTable

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

VB Count query result in a textbox

I want to populate the result of an SQL count query on a Access database in a textbox showing how many results there are. For example I have a code number inputted into the database 200 time, i want the textbox to show 200.
Heres my code so far:
ID = DataGridView1.CurrentRow.Cells(0).Value
fn = DataGridView1.CurrentRow.Cells(1).Value
ln = DataGridView1.CurrentRow.Cells(2).Value
SKU = DataGridView1.CurrentRow.Cells(4).Value
FC = DataGridView1.CurrentRow.Cells(5).Value
Dim countNoTwo As String = "SELECT COUNT skuNo FROM table WHERE skuNo = " & SKU & ""
Dim connection As New OleDbConnection(duraGadgetDB)
Dim dataadapter As New OleDbDataAdapter(countNoTwo, connection)
Dim ds As New DataSet()
connection.Open()
dataadapter.Fill(ds, "dura")
connection.Close()
txtbox1.Text
How do i bind the result of the dataset to the txtbox1.Text?
First, do not use string concatenation to build sql commands
(reason=Sql Injection + Parsing problems)
Second, if your command returns only one single result you could use
ExecuteScalar
Third, use the Using statement to be sure that your connection and
commands are correctly disposed after use
Dim countNoTwo As String = "SELECT COUNT skuNo FROM table WHERE skuNo = ?"
Using connection As New OleDbConnection(duraGadgetDB)
Using command As New OleDbCommand(countNoTwo, connection)
command.Parameters.AddWithValue("#sku", SKU)
connection.Open()
Dim result = Convert.ToInt32(command.ExecuteScalar())
txtbox1.Text = result.ToString
End Using
End Using
Try this
Dim dt As DataTable = ds.Tables(0)
txtbox1.Text = dt.Rows(0).Item(0).ToString()

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.