When I run the query in query analyzer, it returns one row but when I use the same query in VB.NET, no rows are returned - sql

Here is the code:
Function getData(ByVal id As String)
Dim reader As SqlClient.SqlDataReader
Dim statement As String
Dim count As Integer
Dim temp As Integer
statement = "SELECT * FROM General WHERE accountid='" + id + "'"
Conn.Open()
Comm = New SqlClient.SqlCommand(statement, Conn)
reader = Comm.ExecuteReader()
count = reader.FieldCount
Dim Data(count) As String
If reader.HasRows Then
For temp = 0 To count
Data(temp) = (reader.Item(temp))
Next temp
Else
Console.WriteLine("No rows found.")
End If
reader.Close()
Conn.Close()
Return Data
End Function
When I run the code the HasRows field is true but reader.Item(temp) gives the error
Invalid attempt to read when no data is present.

You need a While reader.Read() loop. The reader starts at row index -1; the Read() will advance to the first row (well, fetch it) and then you can process it.
That's why your HasRows returns true but you can't retrieve the fields -- you're not positioned at the first row yet.
You may want to do something like this:
If reader.HasRows Then
While reader.Read()
For temp = 0 To count
Data(temp) = (reader.Item(temp))
Next temp
End While
Else
Console.WriteLine("No rows found.")
End If

Related

Fail auto generate ID

my program fails to auto count my id.Am i missing something. can someone pls help me and take a look
Private Sub getNextNumber()
If Not app.State = ConnectionState.Open Then
'open connection
app.Open()
End If
Dim da As New OleDb.OleDbDataAdapter("select top 1 ID from ADMIN order by ID desc;", app)
Dim dt As New DataTable
'fill data to datatable
da.Fill(dt)
app.Close()
If dt.Rows.Count > 0 Then
txtID.Text = (Val(dt.Rows(0)(0)) + 1).ToString.PadLeft(10, "B")
Else
txtID.Text = "1".PadLeft(10, "B")
End If
End Sub
Private Function getLastNumber() As Integer
Dim app1 As New OleDb.OleDbConnection
app1.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=MYX.accdb"
If Not app1.State = ConnectionState.Open Then
app1.Open()
End If
Dim da As New OleDb.OleDbDataAdapter("select top 1 ID from ADMIN order by ID desc;", app1)
'desc = sort the data returned in descending order
Dim dt As New DataTable
da.Fill(dt)
app1.Close()
If dt.Rows.Count > 0 Then
Return Val(dt.Rows(0)(0))
End If
Return 0
End Function
Have i coded it wrongly in this part?
If dt.Rows.Count > 0 Then
txtID.Text = (Val(dt.Rows(0)(0)) + 1).ToString.PadLeft(10, "B")
Else
txtID.Text = "1".PadLeft(10, "B")
End If
Using...End Using blocks will close and dispose your database objects even if there is an error. You never have to check the state of your connection when you create it locally.
Pass the connection string directly to the constructor of the connection. Likewise, pass the sql statement and the connection directly to the constructor of the command. You don't need a DataAdapter or a DataTable.
.ExecuteScalar returns an object (the first row, first column of the result set) so we declare an Object variable outside the Using block so we can use it after the connection is closed. We can use .ExecuteScalar because you are only returning 1 row and only one column in that row.
Next, after the connection and command are duly closed and disposed, we check if retVal is Nothing and return 0 if is is.
If it passes the nothing test, change to a Char array. Use Linq to extract the numbers for the array. Finally it is joined into one string and converted to a number.
Private conString As String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=MYX.accdb"
Private Function getLastNumber() As Integer
Dim retVal As Object
Using app1 As New OleDb.OleDbConnection(conString)
Using cmd As New OleDbCommand("select top 1 ID from ADMIN order by ID desc;", app1)
app1.Open()
retVal = cmd.ExecuteScalar()
End Using
End Using
If retVal Is Nothing Then
Return 0
End If
Dim arrChar = retVal.ToString.ToCharArray()
Dim result = (From c In arrChar
Where Char.IsNumber(c)
Select c).ToArray
Dim num = CInt(String.Join("", result))
Return num
End Function
Like wise your sub...
Private Sub GetNextID()
Dim retVal As Object
Using app As New OleDbConnection(conString)
Using cmd As New OleDbCommand("select top 1 ID from ADMIN order by ID desc;", app)
app.Open()
retVal = cmd.ExecuteScalar
End Using
End Using
If retVal Is Nothing Then
txtID.Text = "1".PadLeft(10, "B"c)
Return
End If
Dim arrChar As Char() = retVal.ToString.ToCharArray
Dim result = (From c In arrChar
Where Char.IsNumber(c)
Select c).ToArray
Dim num = CInt(String.Join("", result))
txtID.Text = (num + 1).ToString.PadLeft(10, "B"c)
End Sub
I hope this is single user or these methods will have big problems.

Return array of ListViewItem to Sub

I want to make a chart with several series on it. Every series belongs to a particular person.
First I read out the number of different persons in my table in Access:
connection.Open()
command.CommandText = "SELECT kontoverlauf_kunden_id FROM kontoverlauf GROUP BY kontoverlauf_kunden_id"
Dim kunden_id_array As New ArrayList()
reader = command.ExecuteReader()
Do While reader.Read()
kunden_id_array.Add(reader("kontoverlauf_kunden_id").ToString())
Loop
reader.Close()
connection.Close()
Now I have the different persons (the ID of them).
Second I add the series i need to the chart:
For counter As Integer = 0 To kunden_id_array.Count - 1
chartKontoverlauf.Series.Add(New Series("Konto [" & kunden_id_array.Item(counter) & "]"))
chartKontoverlauf.Series(counter).ChartType = SeriesChartType.Line
chartKontoverlauf.Series(counter).Color = Color.Red
chartKontoverlauf.Series(counter).BorderWidth = 3
Next
Now I just need to fill in the points I need, but that's kinda tricky.
I've made a function that will call every time and it reads out the values (money and time) for the particular person. Here's the function first:
Function DatenAuslesen(ByVal kunden_id As Integer) As ListViewItem
Dim lstViewItem As New ListViewItem
Try
connection.Open()
command.CommandText = "SELECT * FROM kontoverlauf WHERE kontoverlauf_kunden_id = " & kunden_id
reader = command.ExecuteReader()
Do While reader.Read()
lstViewItem.SubItems.Add(reader("kontoverlauf_wert").ToString())
lstViewItem.SubItems.Add(reader("kontoverlauf_datum").ToString())
Loop
reader.Close()
connection.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
connection.Close()
Return lstViewItem
End Function
To add the points now, I wrote this little thing:
For counter As Integer = 0 To kunden_id_array.Count - 1
For counter_2 As Integer = 0 To DatenAuslesen(kunden_id_array.Item(counter)).ListView.Items.Count - 1
chartKontoverlauf.Series(counter).Points.AddXY(DatenAuslesen(kunden_id_array.Item(counter)).ListView.Items(counter_2).SubItems(0).Text, DatenAuslesen(kunden_id_array.Item(counter)).ListView.Items(counter_2).SubItems(1).Text)
Next
Next
The problem with the thing is that it just gives me one of the values I need back, and not all. I can't access alle values properly. I'm still not sure if it's even the best variable to do this. I would need an array of ListViewItems to add all of them but I didn't found how to do this.
Maybe anyone has an idea?
Thank you!

Invalid attempt to access a field before calling Read() vb.net

I Got this error not because of code error but because of there is no data in my table
How to check if there is no data and return in variable as 0
here is my code
i am trying to get counter number, but it's error when no records
Public Function GetCount()
Dim count As Integer
Dim cmd As New MySqlCommand
Dim reader As MySqlDataReader = Nothing
Conn.OpenConn()
Dim sqlstr As String
sqlstr = "SELECT counter FROM st_sales ORDER BY salesid DESC LIMIT 1"
Try
'CREATE COMMAND
cmd = New MySqlCommand(sqlstr, Conn.Conn)
reader = cmd.ExecuteReader()
If reader.Read() Then
count = reader.GetInt32(0) + 1
Else
MsgBox("Error")
End If
Finally
reader.Close()
Conn.CloseConn()
End Try
Return count
End Function
Thanks for any healp
try this
If reader.HasRows then
'do the counting
else
count=0
end if

get column value according to another column value from datatable in vb.net

i have a datatable similar to this:
id msg
1 thank you..
2 kindly...
3 please insert..
4 please stop
i need to get a msg according to a specific id from the datatable that's how i'm filling my datatable:
msgTable = selectMsg()
MsgBox(i need to get the msg here)
Public Function selectMsg() As DataTable
Dim command As SqlCommand = New SqlCommand("selectMsg", cn)
command.CommandType = CommandType.StoredProcedure
Dim da As New SqlDataAdapter(command)
'If dt.Rows.Count <> 0 Then
' dt.Rows.Clear()
'End If
Try
da.Fill(msgDS, "N_AI_HOME_CARE")
msgDT = msgDS.Tables(0)
Catch ex As Exception
logFile("SP selectMsg ---" + ex.Message)
End Try
Return msgDT
End Function
any suggestion will be much appreciated !
Supposing that your stored procedure returns the whole datatable of your messages (a very bad move because if the table is big you could have performance and network problems) then you need to apply the Select method with a filter expression to your returned datatable
msgTable = selectMsg()
Dim rows() = msgTable.Select("ID = " & idOfMessage)
if rows.Length > 0 then
MsgBox(row(0)(1).ToString()) ' read the first row, second column of the table'
End If
But I think you should use a more correct approach using a simple ExecuteScalar that doesn't return the entire datatable but just the first row and first column of a query
Public Function selectMsg(idOfMessage as Integer) As String
Dim command As SqlCommand = New SqlCommand("SELECT msg from tableName where ID = #id", cn)
command.Parameters.AddWithValue("#id", idOfMessage)
Dim result = command.ExecuteScalar()
if string.IsNullOrEmpty(result) Then
result = "No message found"
End If
return result
End Function
well acctually i just found that you use
MsgBox(msgTable.Rows(0)(1).ToString())
without any select method :)

Generate custom auto number

I want to generate auto_no by coding.
So I will need to get previous auto_no from sql server then auto_no + 1 to generate next number.
But since my database does not have any record yet. So the temp should be equal to 1.
But why i get temp = 0?
Dim con As New SqlConnection(myConn)
Dim myReader As SqlDataReader
Dim temp As Int64
con.Open()
Dim sql As String = "SELECT MAX(Auto_No) FROM Quotation_No"
Dim comm As SqlCommand = New SqlCommand(sql, con)
con.Open()
myReader = comm.ExecuteReader
If myReader.HasRows Then
Do While myReader.Read()
Loop
Else
temp = 1
End If
Frm1.txtQuotation_No.Text = temp
con.Close()
Get rid of the first call to myReader.Read() that is your problem.
Your reader always returns 1 row (even if there are no rows in the database it will return a result (either 0 or null)).
What your code is doing is as follows:
Executes the command - it returns 1 row.
Calls myReader.Read() which reads the first row
Calls myReader.HasRows which returns true since it has one row
The code enters the if block and calls myReader.Read(), which returns false since you've already read the one row returned in step 4.
The while loop exits.
temp is never set as is left as zero.