ms sql stored procedure return data without output - sql

Hey all i am trying to find examples of getting data back from a stored procedure that has no parameters sent to it nor has any returned output parameter. Though it does display data.
How can i get that from my code im using below?
Dim myCommandSQL As New SqlCommand
Dim myReaderSQL As SqlDataReader = Nothing
Dim intX As Integer = 0
Dim connSql As SqlConnection
Try
connSql = New SqlConnection("Server=sqlprod;" & _
"Database=ISS3_PROD;" & _
"User ID=xxx;" & _
"Password=xxx;" & _
"Trusted_Connection=False;")
connSql.Open()
myCommandSQL.CommandType = CommandType.StoredProcedure
myCommandSQL.CommandText = "Select_Prod"
Dim sqlParReturn1 As System.Data.SqlClient.SqlParameter = myCommandSQL.Parameters.Add("#return_value", SqlDbType.VarChar)
sqlParReturn1.Direction = ParameterDirection.Output
myCommandSQL.ExecuteNonQuery()
MsgBox(sqlParReturn1)
connSql.Close()
myCommandSQL.Dispose()
The #return_value i just put there to see what would happen but i got nothing returned.
Any help would be great!
David

If you assign a parameter to your command, then your stored procedure should take a parameter. Furthermore, if you specify the direction as Output, then you should mark that parameter as OUTPUT in your stored procedure.
If you just want the results of a stored procedure that doesn't take any parameters, then remove all the lines that include sqlParReturn1. Also, your command isn't a "non-query" -- you are querying for data. To get it, you should do this (I also refactored your code using some better-practice techniques):
Using connSql As SqlConnection = New SqlConnection(...)
connSql.Open()
Using myCommandSQL As SqlCommand = connSql.CreateCommand()
myCommandSQL.CommandType = CommandType.StoredProcedure
myCommandSQL.CommandText = "Select_Prod"
Using reader As SqlDataReader = myCommandSQL.ExecuteReader()
If reader.HasRows Then
While reader.Read()
// loops through the rows returned
End While
End If
End Using
End Using
End Using

Here is the MSDN documentation on reading data using an ADO datareader. I think their example explains this quite well, so I have just copy and pasted the example here. Just replace your SQL setup, and then you just need to call the ExecuteReader, followed by a while loop that runs while reader.Read finds rows. Just inside the loop, you can then access your columns via reader.Get..., using ordinals or columnnames.
Private Sub HasRows(ByVal connection As SqlConnection)
Using connection
Dim command As SqlCommand = New SqlCommand( _
"SELECT CategoryID, CategoryName FROM Categories;", _
connection)
connection.Open()
Dim reader As SqlDataReader = command.ExecuteReader()
If reader.HasRows Then
Do While reader.Read()
Console.WriteLine(reader.GetInt32(0) _
& vbTab & reader.GetString(1))
Loop
Else
Console.WriteLine("No rows found.")
End If
reader.Close()
End Using
End Sub

Related

Performance issue with SQLite database with VB.NET

I am Inserting the data-table into SQLite Database. I am doing like this.
First I Fetch the data with getdata function and insert it into datatable, then with For Each Loop i made the Insert Command and Execute It. I am having 50000 Records it will take 30 Minutes to run.
Please Guide the suitable approach. Here is the Code.
Dim xtable As DataTable = getdata("select * from tablename")
Dim str As String = Nothing
For Each r As DataRow In xtable.Rows ''''HERE IT WILL TAKE TOO MUCH TIME
str = str & ("insert into tablename values(" & r.Item("srno") & "," & r.Item("name"));")
Next
EXECUTEcmd(str)
Public Function getdata(ByVal Query As String) As DataTable
connectionString()
Try
Dim mds As New DataTable
Dim mycommand As New SQLiteCommand(DBConn)
mycommand.CommandText = Query
Dim reader As SQLiteDataReader = mycommand.ExecuteReader()
mds.Load(reader)
Return mds
Catch ex As Exception
MsgBox("DB Error", vbCritical, "")
MsgBox(Err.Description)
Return Nothing
End Try
End Function
Public Sub EXECUTEcmd(ByVal selectcmd As String)
Using cn = New SQLiteConnection(conectionString)
cn.Open()
Using transaction = cn.BeginTransaction()
Using cmd = cn.CreateCommand()
cmd.CommandText = selectcmd
cmd.ExecuteNonQuery()
End Using
transaction.Commit()
End Using
cn.Close()
End Using
End Sub
here the Conncection String is:
conStr = "Data Source=" & dbpath & ";Version=3;Compress=True; UTF8Encoding=True; PRAGMA journal_mode=WAL; cache=shared;"
Use a stringbuilder to build your string, not string concatenation
Dim strB As StringBuilder = New StringBuilder(100 * 50000)
For Each r As DataRow In xtable.Rows
strB.AppendLine($"insert into tablename values({r.Item("srno")},{r.Item("name")});")
Next
Strings cannot be changed in .net. Every time you make a new string VB has to copy everything out of the old string into a new one and add the new bit you want. If each of your insert statements is 100 bytes, that means it copies 100 bytes, then adds 100, then copies 200 bytes and adds 100, then copies 300 bytes, then 400 bytes, then 500 bytes. By the time it has done 10 strings it has made 5.5 kilobytes of copying. By the time it's done 50 thousand strings it has copied 125 gigabytes of data. No wonder it's slow!
Always use a StringBuilder to build massive strings
--
I'm willing to overlook the sql injection hacking nag for this one, because of the nature of the task, but please read http://bobby-tables.com - you should never, ever concatenate values into an SQL as a way of making an sql that has some varying effect.
This entire exercise would be better done as this (pseudocode) kind of thing:
Dim sel as New SQLiteCommand("SELECT a, b FROM table", conn)
Dim ins as New SQLiteCommand("INSERT INTO table VALUES(:a, :b)", conn)
ins.Parameters.Add("a" ...)
ins.Parameters.Add("b" ...)
Dim r = sel.ExecuteReader()
While r.Read()
ins.Parameters("a") = r.GetString(0)
ins.Parameters("b") = r.GetString(1)
ins.ExecuteNonQuery()
End While
That is to say, you minimize your memory by reading rows one at a time out of ther edaer and inserting them one at a time in the insert; the insert command is prepared once, you just change the parameter values, execute it, change them again, execute it ... It's what parameterized queries were designed for (as well as stopping your app getting hacked when someone puts SQL in your variable, or even just stopping it crashing when you have an person named O'Grady
Maybe you must refactor your code like this:
Dim xtable As DataTable = getdata("select * from tablename")
Using cn = New SQLiteConnection(conectionString)
cn.Open()
Using transaction = cn.BeginTransaction()
Try
Using cmd = cn.CreateCommand()
cmd.Transaction = transaction
For Each r As DataRow In xtable.Rows ''''HERE IT WILL TAKE TOO MUCH TIME
cmd.CommandText = "insert into tablename values(" & r.Item("srno") & "," & r.Item("name") & ")"
cmd.ExecuteNonQuery()
Next
End Using
transaction.Commit()
Catch ex As Exception
transaction.Rollback()
End Try
End Using
End Using
Public Function getdata(ByVal Query As String) As DataTable
connectionString()
Try
Dim mds As New DataTable
Dim mycommand As New SQLiteCommand(DBConn)
mycommand.CommandText = Query
Dim reader As SQLiteDataReader = mycommand.ExecuteReader()
mds.Load(reader)
Return mds
Catch ex As Exception
MsgBox("DB Error", vbCritical, "")
MsgBox(Err.Description)
Return Nothing
End Try
End Function
Instead of concatenate an possible giant string, wrap all your inserts into a single transaction, like above. This will reduce the memory used and also make sqlite perform faster.

Reading from a database and using an if statement

The program currently reads from the database, but what I am trying to do is try to get the program to read from the database and if the field is empty then output "TBC" and if not then it will show the grade. I'm unsure of how to check what dr.Read is and use an if statement with it.
Sub GradeResult()
Dim dr As OleDbDataReader
Dim cm As New OleDbCommand
Dim cn As New OleDbConnection
cn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=login.accdb"
cn.Open()
cm.CommandText = "SELECT ArGrade FROM loginDetails WHERE UserName = '" & username & "'"
cm.Connection = cn
dr = cm.ExecuteReader
dr.Read()
Label6.Text = dr.Item("ArGrade")
End Sub
Instead of using an if statement, when the user registers, the program writes TBC into the field.
dr is an instance of the OleDbDataReader class, and Read is one public method of this class. You need to call it in order to start reading the results after a query is executed against the database.
From the OleDbDataReader.Read documentation page:
Advances the OleDbDataReader to the next record.
You need to call it at least once, to get some results.
Returns
Boolean
true if there are more rows; otherwise, false.
Use it to check if you have any results at all or more results as one.
The default position of the OleDbDataReader is before the first record. Therefore, you must call Read to start accessing any data.
In your case you can check if there is any result like this:
Label6.Text = "TBC" ' standard value is no value found
if dr.Read() then ' DB contains any rows
dim arGrade = dr.Item("ArGrage")
if not IsDbNull(arGrade) then ' and the ArGrade has a value
Label6.Text = arGrade
end if
end if
And don't forget to close the reader with dr.Close.

Converting VBA function to VB.net to get sql data

I am trying to convert VBA code into VB.net and I have made it to a point but I can't convert resultset into vb.net. RS was 'dim as resultset' in VBA, thought i could just change it to dataset but am getting errors with the '.fields' and other options?
Function GetG(sDB As String, sServ As String, sJob As String) As String
'sDB = Database name, sServ = Server\Instance, path = job.path
Dim conString As String = ("driver={SQL Server};server = " &
TextBox1.Text & " ; uid = username;pwd=password:database = " &
TextBox2.Text)
Dim RS As DataSet
Dim conn As SqlConnection = New SqlConnection(conString)
Dim cmd As SqlCommand
conn.Open()
'This is where my problems are occuring
cmd = New SqlCommand("SELECT [ID],[Name] FROM dbo.PropertyTypes")
Do While Not RS.Tables(0).Rows.Count = 0
If RS.Fields(1).Value = sJob Then
GetG = RS.Fields(0).Value
GetG = Mid(GetG, 2, 36)
Exit Do
End If
DataSet.MoveNext
Loop
conn.Close
End Function
Based on my understanding and some guesswork, here is what I came up with for what I think you're wanting.
As I stated in my comment above, it appears you can just use a WHERE clause to get the exact record you want (assuming a single instance of sJob appears in the name column).
Build the connectionstring off the input arguments, not controls on your form. That is after all why you allow for arguments to be passed along. Also note that there is a SqlCommandBuilder object that may be of interest. But for now
Function GetG(sDB As String, sServ As String, sJob As String) As String
'we'll pretend your connectionstring is correct based off of the sDB and sServ arguments
Dim conStr As String = ("driver={SQL Server};server = " & sServ & " ; uid = username;pwd=password:database = " & sDB)
'Create a connection and pass it your conStr
Using con As New SqlConnection(conStr)
con.Open() 'open the connection
'create your sql statement and add the WHERE clause with a parameter for the input argument 'sJob'
Dim sql As String = "SELECT [ID], [Name] FROM dbo.PropertyTypes WHERE [Name] = #job"
'create the sqlCommand (cmd) and pass it your sql statement and connection
Using cmd As New SqlCommand(sql, con)
'add a parameter so the command knows what #job holds
cmd.Parameters.Add(New SqlParameter("#job", SqlDbType.VarChar)).Value = sJob
'Now that have the command built, we can pass it to a reader object
Using rdr As SqlDataReader = cmd.ExecuteReader
rdr.Read()
'i admin i'm a little confused here on what you are
'trying to achieve so ID may not be what you are
'really wanting to get a substring of.
Return rdr("ID").ToString.Substring(2, 36)
End Using
End Using
End Using
End Function
An example to see if this is working could be to call a messagebox do display the result. For this example, I'm going to pretend that TextBox3 holds the sJob you're wanting. With that knowledge, you could simply do:
MessageBox.Show(GetG(TextBox2.Text, TextBox1.Text, TextBox3.Text))
This should then produce the result in a messagebox.
It seems that you're not filling your DataSet. So, when you try to loop through it, it's uninitialized or empty.
Check this answer to see an example: Get Dataset from DataBase

Retrieve data from database in asp.net using vb

Below is the code for fetching the data into textbox but its not working it shows error no data exits row/column whereas data and datafield are perfectly alright.
Please help.
Dim Connection As OleDbConnection
Connection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath("/db/QardanHasana.mdb"))
Connection.Open()
Dim ejamaatregcmd As OleDbCommand
Dim ejamaatregdtrdr As OleDbDataReader
ejamaatregcmd = New OleDbCommand("SELECT ITSData.[EJamaatID], ITSData.[ITSFirstName] FROM ITSData WHERE EjamaatID= #EjamaatID", Connection)
ejamaatregcmd.Parameters.Add(New OleDbParameter("#EjamaatID", txtEjamaatID.Text))
ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.HasRows Then
txtFirstName.Text = ejamaatregdtrdr.item("ITSFirstName").ToString()
end if
A DataReader needs a call to Read to position itself on the first record retrieved
ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.HasRows Then
ejamaatregdtrdr.Read()
txtFirstName.Text = ejamaatregdtrdr.item("ITSFirstName").ToString()
End if
By the way, Read returns false if there are no rows to read, so you could remove the test for HasRows and write simply
ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.Read() Then
txtFirstName.Text = ejamaatregdtrdr.item("ITSFirstName").ToString()
End if
Another suggestion to improve your code is to start using the Using Statement
Using Connection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;....")
Using ejamaatregcmd = new OleDbCommand("SELECT ITSData.[EJamaatID], ITSData.[ITSFirstName] FROM ITSData WHERE EjamaatID= #EjamaatID", Connection)
Connection.Open()
ejamaatregcmd.Parameters.Add(New OleDbParameter("#EjamaatID", txtEjamaatID.Text))
Using ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.Read() Then
txtFirstName.Text = ejamaatregdtrdr.item("ITSFirstName").ToString()
End if
End Using
End Using
End Using
The using statement is invaluable to help you to close and dispose the disposable objects like the connection, the command and the reader. Lacking a proper dispose your code uses more memory and locks resources resulting in a more unstable application.
Before reading data from a DataReader, you need to move the row to the first row by calling the Read method. It returns true if data exist, so you don't need to check the HasRows property:
ejamaatregdtrdr = ejamaatregcmd.ExecuteReader()
If ejamaatregdtrdr.Read() Then
txtFirstName.Text = ejamaatregdtrdr.Item("ITSFirstName").ToString()
End if
I'll generally do something like the following
Function GetResult(ID As string) As String
GetResult = "No Data" 'Default Result
Dim conn As System.Data.OleDb.OleDbConnection = *NewConnectionObject*
Dim comm As System.Data.OleDb.OleDbCommand = *NewCommmandObject*
comm.Parameter.AddWithValue("#Parametername",ID)
Using reader As System.Data.OleDb.OleDbDataReader = comm.ExecuteReader()
If reader.HasRows Then
'Reader has data, so iterate through it
GetResult = ""
while reader.read
GetResult += reader("FirstName")
End While
Else
'Either Do Nothing - Default Result will show
'Throw New System.Exception("Empty Data") 'Try Catch Statement have overhead.. so it's not a popular methodology
'Or Log Something..
End If
End Using
If conn.state = connection.open Then
conn.close
End
End Function

How do I assign the results of an SQL query to multiple variables in VB.NET?

This is my first attempt at writing a program that accesses a database from scratch, rather than simply modifying my company's existing programs. It's also my first time using VB.Net 2010, as our other programs are written in VB6 and VB.NET 2003. We're using SQL Server 2000 but should be upgrading to 2008 soon, if that's relevant.
I can successfully connect to the database and pull data via query and assign, for instance, the results to a combobox, such as here:
Private Sub PopulateCustomers()
Dim conn As New SqlConnection()
Dim SQLQuery As New SqlCommand
Dim daCustomers As New SqlDataAdapter
Dim dsCustomers As New DataSet
conn = GetConnect()
Try
SQLQuery = conn.CreateCommand
SQLQuery.CommandText = "SELECT Customer_Name, Customer_ID FROM Customer_Information ORDER BY Customer_Name"
daCustomers.SelectCommand = SQLQuery
daCustomers.Fill(dsCustomers, "Customer_Information")
With cboCustomer
.DataSource = dsCustomers.Tables("Customer_Information")
.DisplayMember = "Customer_Name"
.ValueMember = "Customer_ID"
.SelectedIndex = -1
End With
Catch ex As Exception
MsgBox("Error: " & ex.Source & ": " & ex.Message, MsgBoxStyle.OkOnly, "Connection Error !!")
End Try
conn.Close()
End Sub
I also have no problem executing a query that pulls a single field and assigns it to a variable using ExecuteScalar. What I haven't managed to figure out how to do (and can't seem to hit upon the right combination of search terms to find it elsewhere) is how to execute a query that will return a single row and then set various fields within that row to individual variables.
In case it's relevant, here is the GetConnect function referenced in the above code:
Public Function GetConnect()
conn = New SqlConnection("Data Source=<SERVERNAME>;Initial Catalog=<DBNAME>;User Id=" & Username & ";Password=" & Password & ";")
Return conn
End Function
How do I execute a query so as to assign each field of the returned row to individual variables?
You probably want to take a look at the SqlDataReader:
Using con As SqlConnection = GetConnect()
con.Open()
Using cmd As New SqlCommand("Stored Procedure Name", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("#param", SqlDbType.Int)
cmd.Parameters("#param").Value = id
' Use result to build up collection
Using dr As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection Or CommandBehavior.SingleResult Or CommandBehavior.SingleRow)
If (dr.Read()) Then
' dr then has indexed columns for each column returned for the row
End If
End Using
End Using
End Using
Like #Roland Shaw, I'd go down the datareader route but an other way.
would be to loop through
dsCustomers.Tables("Customer_Information").Rows
Don't forget to check to see if there are any rows in there.
Google VB.Net and DataRow for more info.