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

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

Related

vb.net Loading Images from Access Database to DataTable?

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

How to specify field data type when reading from a SQL database

I have a SQL table called "Customers". In it is a CustomerNumber field with values like "0001234567", i.e. they are made up of numbers only, but some include leading 0s. So, when I try to run something like
sqlFetch(channel=myconn, sqtable="Customers", stringsAsFactors=FALSE)
it returns my customers table where the CustomerNumber field is numeric (instead of character), and consequently I lose all those leading 0s.
Is there a way I can specify the fieldtype for a column or an alternative solution that won't truncate all my leading 0s?
You can control the types of columns more fully using the as.is argument, which is documented in the Details section of ?sqlFetch as well as at the linked documentation for ?sqlQuery and ?sqlGetResults.
Basically, it is either a vector of logicals or a vector of numeric or character indices specifying which columns to leave untouched. This vector will be recycled as necessary.
(Note that RODBC will clobber columns stored in the database with type.convert even if the C API correctly returns char or varchar as the data type of the column in the database. The maintainer has not responded to any of my 4-5 emails on this issue over the past year, and I have since simply used a forked version of RODBC with the needed one line modification ever since.)
You could try specifying a query string and you could even cast the field if you're still having problems.
Sub Main()
Dim myConn As String = System.Configuration.ConfigurationSettings.AppSettings.Get("ConnStr")
Dim sqlConnection As SqlConnection = New SqlConnection(myConn)
Dim strSQL As String = "select cast(CustomerNumber as varchar(30)) as CustomerNumber_varchar, * from Customers"
Dim myds As DataSet
sqlConnection.Open()
Dim cmd As SqlCommand = New SqlCommand(strSQL, sqlConnection)
cmd.CommandTimeout = 60
Dim myReader As SqlDataReader = cmd.ExecuteReader()
myds = ConvertDataReaderToDataSet(myReader)
myReader.Close()
End Sub
Public Function ConvertDataReaderToDataSet(ByVal reader As SqlDataReader) As DataSet
Dim dataSet As DataSet = New DataSet()
Dim schemaTable As DataTable = reader.GetSchemaTable()
Dim dataTable As DataTable = New DataTable()
Dim intCounter As Integer
For intCounter = 0 To schemaTable.Rows.Count - 1
Dim dataRow As DataRow = schemaTable.Rows(intCounter)
Dim columnName As String = CType(dataRow("ColumnName"), String)
Dim column As DataColumn = New DataColumn(columnName, _
CType(dataRow("DataType"), Type))
dataTable.Columns.Add(column)
Next
dataSet.Tables.Add(dataTable)
While reader.Read()
Dim dataRow As DataRow = dataTable.NewRow()
For intCounter = 0 To reader.FieldCount - 1
dataRow(intCounter) = reader.GetValue(intCounter)
Next
dataTable.Rows.Add(dataRow)
End While
Return dataSet
End Function

Error loading sql parameters in a loop, VB.Net

I am currently working in Microsoft visual studio express 2013 with an sql back end. I am trying to run a loop through 2 comboboxes and a datetimepicker for any instance a checkbox is checked. However, I am running into an error that reads "System.ArgumentException: No Mapping exists from Object type system.windows.forms.datetimepicker to a known managed provider native type." When I run the code I have put a watch on the parameter value and it is not saving the data into the variable before the sql command fires. I think I need to store the variable in a different way to allow access to the variable. Here is my code:
Try
Using conn1 As New SqlConnection(connstring)
conn1.Open()
Using comm1 As New SqlCommand("SELECT isnull(max(AuditID) + 1, 1) as 'AuditID' FROM table1", conn1)
Dim reader1 As SqlDataReader = comm1.ExecuteReader
reader1.Read()
Dim AuditID As Integer = reader1("AuditID")
reader1.Dispose()
'Loop through all checkboxes and write into sql tables
Dim Run As Integer
For Run = 1 To 5
Dim LineItem = DirectCast(Me.Controls("CB" & Run), CheckBox)
If LineItem.Checked = True Then
Dim DateTime = DirectCast(Me.Controls("DTP" & Run), DateTimePicker)
Dim Frequency = DirectCast(Me.Controls("CBWeek" & Run), ComboBox)
Dim Repeat = DirectCast(Me.Controls("CBRepeat" & Run), ComboBox)
'sql statements
'select ID
Using conn2 As New SqlConnection(connstring)
conn2.Open()
Using comm2 As New SqlCommand("SELECT isnull(max(AuditID) + 1, 1) as 'ID' FROM table1", conn1)
Dim reader As SqlDataReader = comm2.ExecuteReader
reader.Read()
Dim ID As Integer = reader("ID")
reader.Dispose()
'Insert into table audit line
Using conn3 As New SqlConnection(connstring)
conn3.Open()
Using comm3 As New SqlCommand("INSERT INTO table1 (ID, AuditID, DateStart, Freq, repeats) " _
& "VALUES (#ID, #AuditID, #DateStart, #Freq, #Repeats)", conn3)
With comm3.Parameters
.AddWithValue("#ID", ID)
.AddWithValue("#AuditID", AuditID)
.AddWithValue("#DateStart", DateTime)
.AddWithValue("#Freq", Frequency)
.AddWithValue("#Repeats", Repeat)
End With
comm3.ExecuteNonQuery()
End Using
conn3.Close()
End Using
End Using
conn2.Close()
End Using
End If
Next
End Using
conn1.Close()
End Using
Catch ex As Exception
MsgBox(ex.ToString)
My try statement stop my code on this line:
comm3.ExecuteNonQuery()
However, I know that this error is coming from when I add my parameters, specifically these 3 lines:
.AddWithValue("#DateStart", DateTime)
.AddWithValue("#Freq", Frequency)
.AddWithValue("#Repeats", Repeat)
I am trying to get tese variables with a loop statement based on the design name here:
Dim DateTime = DirectCast(Me.Controls("DTP" & Run), DateTimePicker)
Dim Frequency = DirectCast(Me.Controls("CBWeek" & Run), ComboBox)
Dim Repeat = DirectCast(Me.Controls("CBRepeat" & Run), ComboBox)
It does not seem like the program likes using these dimensions above to be inserted into the sql table. Does anyone know a way I can carry these values over to the sql parameters statement?
There are a number of things I would do differently. First and always, use Option Strict, it will catch some of the type conversion you have going on.
I would get the controls from an explicit list rather then fetching from Controls. Just make a few arrays to hold the control refs so you do not need to to find them in the collection:
Private DTPs As DateTimePicker() = {DTP1, DTP2...}
This will avoid the need to cast them, fewer hoops and implied converts like "DTP" & Run:
Dim dt As DateTime ' vars for the SQL
Dim freq As Integer
For Run As Integer = 0 To 4
dt = DTPs(Run).Value
freq = cboFreq(Run).SelectedValue
...
I have fixed the problem, I needed to put my loop variables into .value type variables. I added this to fix it:
Dim DateTime = DirectCast(Me.Controls("DTP" & Run), DateTimePicker)
Dim Frequency = DirectCast(Me.Controls("CBWeek" & Run), ComboBox)
Dim Repeat = DirectCast(Me.Controls("CBRepeat" & Run), ComboBox)
Dim Time As Date = DateTime.Value
Dim Freq As Integer = Frequency.SelectedValue
Dim Again As Integer = Repeat.SelectedValue

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 - "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.