How do I retrieve a value from an SQL query and store it in a variable in VB.NET? - sql

I am trying to find the max product ID and store the value in a local variable "MaxID" and return this value. I am trying to convert the result of the query into an Integer type but I am not able to do it. Below is the code:
Public Function GetMaxID(ByVal TableName As String, ByVal ID As String) As Integer
Dim MaxID As Integer
Dim sqlquery As SqlCommand
Dim field_name As String = ID
Dim con As SqlConnection
con = New SqlConnection()
con.ConnectionString = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename='D:\Docs Dump\Work\Srinath\SrinathDB.mdf';Integrated Security=True;Connect Timeout=30"
con.Open()
Try
sqlquery = New SqlCommand("SELECT MAX( #field ) FROM #table ", con)
sqlquery.Parameters.AddWithValue("#field", field_name)
sqlquery.Parameters.AddWithValue("#table", TableName)
MaxID = CInt(sqlquery.ToString)
con.Close()
Return MaxID
Catch ex As Exception
Return 0
Exit Function
con.Close()
End Try
End Function
End Class

MaxID = CInt(sqlquery.ExecuteScalar())
You also should know about SqlCommand.ExecuteReader(), SqlCommand.ExecuteNonQuery() (for inserts/updates/deletes), and SqlDataAdapter.Fill().
Where you'll still have a problem is you can't use a parameter value for the table name or column name. The Sql Server engine has a "compile" step, where it has to be able to work out an execution plan, including permissions/security, at the beginning of the query, but variable names like #table and #field aren't resolved until later. It's not what actually happens, but think of it as if you had string literals in those places; imagine trying to run this:
SELECT MAX('ID') FROM 'MyTable'
MAX('ID') will always return the string value ID, and not anything from an ID column in any rows. But the MyTable part is not the correct place for a string literal, and such a query wouldn't even compile.
I also see people here from time to time try to create functions like GetMaxId(), and it's almost always misguided in the first place. If the intended use for this function is the same as what I usually see, you're setting up a major race condition issue in your application (one that probably won't show up in any testing, too). Sql Server gives you features like identity columns, sequences, and the scope_identity() function. You should be using those in such a way that new IDs are resolved on the server as they are created, and only (and immediately) then returned to your application code.
But that issue aside, here's a better way to structure this function:
Public Class DB
Private conString As String = "Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename='D:\Docs Dump\Work\Srinath\SrinathDB.mdf';Integrated Security=True;Connect Timeout=30"
'You want a separate method per-table that already knows the table and column names
Public Function GetMyTableMaxID() As Integer
Dim sql As String = "SELECT MAX(ID) FROM MyTable"
Using con As New SqlConnection(conString), _
sqlQuery As New SqlCommand(sql, con)
'Parameters would go here.
'Do NOT use AddWithValue()! It creates performance issues.
' Instead, use an Add() overload where you provide specific type information.
'No exception handling at this level. The UI or business layers are more equipped to deal with them
con.Open()
Return CInt(sqlQuery.ExecuteScalar())
End Using
'No need to call con.Close()
'It was completely missed in the old code, but handled by the Using block here
End Function
End Class

Related

Is there any SQL Statement procedure or code for optional requested field value?

I'm a beginner. I created a database in vb.net and I need to build a query, in the SQL Statement - Table Adapter, which returns records even if parameters are NULL in one or more textbox. To be clear, I have several textboxes (related to fields) with which I can filter record results and I want to refine my research as much as I fill textboxes, reverse if I fill just one of them randomly.
Sorry if I confused you, but I guess you get it anyway.
In its simplest form (assuming SQL server param concepts)
-- Define your columns to pull back/display
select t1.column1, t1.column2, t1.column3...
-- Define the table, give it an alias if you're using more than one or it has a silly name
from thetable t1
-- Apply filters
where
-- For each textbox/column search combo, do this...
(column1 = #field1 or #field1 is null)
or -- If the filter is restrictive, use AND here
(column2 = #field2 or #field2 is null)
or -- If the filter is restrictive, use AND here
...
I would dump the table adapter for this requirement.
I am building the sql string using a StringBuilder. StringBuilder objects are mutable, String is not.
To run this Code
1. I assumed Sql Server. If this is not the case change all the data object (Connectio and Command) to the proper provider.
Add your connection string to the constructor of the connection.
Add your table name where it says "YourTable"
I just used TextBox1 etc. as control names. Use your actual control names
Replace Field1, Field2 etc. with your actual column names.
The parameter names (by convention, they start with #) can be anything you want as long as they match the name you add to the Parameters collection.
You will have to check your database for the actual datatypes of the fields. Be sure to convert the TextBox values to the compatible type. TextBox.Text is a string so it will be compatible to .VarChar but note number types or dates.
I added a Debug.Print to check what the Sql string looks like. Be cautious about where I have spaces when building the string. You can see the result in the immediate window (available from Debug menu).
If you don't already have a DataGridView on your form, add one so you can see the reults of your query.
Finally, always use parameters, use Using...End Using blocks, and open your connection at the last minute.
Private Sub RunDynamicQuery()
Dim sb As New StringBuilder
Dim AndNeeded As Boolean
Dim dt As New DataTable
Using cn As New SqlConnection("Your connection string")
Using cmd As New SqlCommand
sb.Append("Select * From YourTable Where ")
If Not String.IsNullOrEmpty(TextBox1.Text) OrElse Not String.IsNullOrWhiteSpace(TextBox1.Text) Then
sb.Append("Field1 = #Field1")
cmd.Parameters.Add("#Field1", SqlDbType.Int).Value = CInt(TextBox1.Text)
AndNeeded = True
End If
If Not String.IsNullOrEmpty(TextBox2.Text) OrElse Not String.IsNullOrWhiteSpace(TextBox2.Text) Then
If AndNeeded Then
sb.Append(" And")
End If
sb.Append(" Field2 = #Field2")
cmd.Parameters.Add("#Field2", SqlDbType.VarChar).Value = TextBox2.Text
AndNeeded = True
End If
If Not String.IsNullOrEmpty(TextBox3.Text) OrElse Not String.IsNullOrWhiteSpace(TextBox3.Text) Then
If AndNeeded Then
sb.Append(" And")
End If
sb.Append(" Field3 = #Field3")
cmd.Parameters.Add("#Field3", SqlDbType.VarChar).Value = TextBox3.Text
AndNeeded = True
End If
sb.Append(";")
cmd.Connection = cn
Debug.Print(sb.ToString)
cmd.CommandText = sb.ToString
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
End Using
DataGridView1.DataSource = dt
End Sub

Inserting data in mysql using vb.net (n-tier)

there's anyone can help me with my vb.codes? i'm new in vb.net and i want to know how to add data in mysql database using n-tier in vb.net. this is may current code in adding data:
Data Layer:
Public Function addData() As DataTable
Dim myCommand As String = "Insert Into tblItems VALUES (#Itemcode, #Itemname, #Itemdescription, #Itemtype, #Itempricing, #Itemonstock, #Itemprice, #Datemod)"
con.Open()
Dim sda As New MySqlDataAdapter(myCommand, con)
Dim dt As DataTable = New DataTable
sda.Fill(dt)
Return dt
End Function
sorry for my code. i really don't know how can i use that in BLL and PL. please help me. i really want to learn from all of you guys..
PS: sorry for my english i'm a 14 yr old and i want to learn programming. i did a research but i can't find what i'm really looking for. thanks in advance.
To insert a new record in a datatable you need to execute a command and provide the values to be sent to the database table.
You need something like this.
Public Function addData(itmCode as String, itmName as String.... omitted the other values) As Integer
Dim myCommand As String = "Insert Into tblItems VALUES " & _
"(#Itemcode, #Itemname, #Itemdescription, " & _
"#Itemtype, #Itempricing, #Itemonstock, #Itemprice, #Datemod)"
con.Open()
Dim cmd As New MySqlCommand(myCommand, con)
cmd.Parameters.AddWithValue("#ItemCode", itmCode)
cmd.Parameters.AddWithValue("#ItemName", itmName)
.... other parameters for the other values to insert will follow....
Dim rowInserted = cmd.ExecuteNonQuery()
return rowInserted
End Function
This requires that you pass to the function the values through a set of variables which values are added to the parameter collection of the command and finally execute the command.
The execution returns the number of records inserted/changed/deleted.
Notice also that your query doesn't specify a field list, so you need to pass the values to update every single field in the underlying datatable with the exact order.

Vb.net pull in a SQL table row by row

I am a little new to using vb.net and SQL so I figured I would check with you guys to see if what I am doing makes sense, or if there is a better way. For the first step I need to read in all the rows from a couple of tables and store the data in the way the code needs to see it. First I get a count:
mysqlCommand = New SQLCommand("SELECT COUNT(*) From TableName")
Try
SQLConnection.Open()
count = myCommand.ExecuteScalar()
Catch ex As SqlException
Finally
SQLConnection.Close()
End Try
Next
Now I just want to iterate through the rows, but I am having a hard time with two parts, First, I cannot figure out the SELECT statement that will jet me grab a particular row of the table. I saw the example here, How to select the nth row in a SQL database table?. However, this was how to do it in SQL only, but I was not sure how well that would translate over to a vb.net call.
Second, in the above mycommand.ExecuteScalar() tell VB that we expect a number back from this. I believe the select statement will return a DataRow, but I do not know which Execute() statement tells the script to expect that.
Thank you in advance.
A simple approach is using a DataTable which you iterate row by row. You can use a DataAdapter to fill it. Use the Using-statement to dispose/close objects property that implement IDisposable like the connection:
Dim table = New DataTable
Using sqlConnection = New SqlConnection("ConnectionString")
Using da = New SqlDataAdapter("SELECT Column1, Column2, ColumnX FROM TableName ORDER By Column1", sqlConnection)
' you dont need to open/close the connection with a DataAdapter '
da.Fill(table)
End Using
End Using
Now you can iterate all rows with a loop:
For Each row As DataRow In table.Rows
Dim col1 As Int32 = row.Field(Of Int32)(0)
Dim col2 As String = row.Field(Of String)("Column1")
' ...'
Next
or use the table as DataSource for a databound control.

Select Statement SQL in VB

I understand that there are other posts such as this, however I cannot find one that will work for me and Im really at the end of my tether with this, I really dont know what to do.
I have a few tables with ID columns and name columns, that are connected by Link Tables through foreign keys etc. I'm trying to enter data into the database via a GUI and to do so I'm using insert statements into the 'regular' tables, then Select statements to get the autogen IDs from the regular table to then insert into the link tables.
The code below is what I've been trying to use to do this.
Imports System.Data.SqlClient
Public Class Test
Private cs As New SqlConnection(".....")
Private Sub btnInsertNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnInsertNext.Click
Dim ContID As Integer
Dim FName As Integer
cs.Open()
Using command As New SqlCommand("Select FamID From Family Where Name = '" & FName & " '", cs)
command.Parameters.AddWithValue("#FamID", ContID)
command.ExecuteNonQuery()
End Using
Using command As New SqlCommand("Select DocID From Doctors Where DocName LIKE'" & AddFam.Doctor & " '", cs)
command.Parameters.AddWithValue("#DocID", AddFam.Doctor) ''AddFam is another form I'm using to add a family member to a Doctor
command.ExecuteNonQuery()
End Using
cs.close()
I'm using:
VB 2010
SQL server management 2008 r2
I understand its a bit muddley but any help would be greatly appreciated, and I'm sorry if this has come up before.
It's not really clear what problem you actually have, i assume that you don't know how to retrieve newly generated IDs.
Here is an self-explanatory example on how to retrieve new identity values with ADO.NET:
Using con = New SqlConnection(connectionString)
Dim newID As Int32
Using insertCommand = New SqlCommand("INSERT INTO Test(Value)VALUES(#Value);SELECT CAST(scope_identity() AS int)", con)
insertCommand.Parameters.AddWithValue("#Value", "Value1")
con.Open()
newID = DirectCast(insertCommand.ExecuteScalar, Int32)
End Using
If newID <> 0 Then
Using updateCommand = New SqlCommand("UPDATE TEST SET Value='Value1.1' WHERE idTest=#idTest", con)
updateCommand.Parameters.AddWithValue("#idTest", newID)
If con.State <> ConnectionState.Open Then con.Open()
Dim updatedRecordCount = updateCommand.ExecuteNonQuery
End Using
End If
End Using
The 2 important parts are:
SELECT CAST(scope_identity() AS int)
which will return the new identity value
DirectCast(insertCommand.ExecuteScalar, Int32)
which will return the new Identity column value if a new row was inserted, 0 on failure.
Since you're mixing using parameters with string-concatenation: using parameters is very important because it will prevent SQL-Injection.
SCOPE_IDENITY
ExceuteScalar-Method
Commands and Parameters in ADO.NET
NO! Parameterise your queries like this.
command = New SqlCommand("Select FamID From Family Where Name = #Fname", cs)
command.Parameters.AddWithValue("#Fname", ContID)
FamID = command.ExecuteScalar()
And ideally, you should use Scope_Identity() to get the Identity from you insert statement
You can try with this code on two queries based on # symbol
...
Using command As New SqlCommand("Select FamID From Family Where Name = #FamID", cs)
command.Parameters.AddWithValue("#FamID", ContID)
...
Using command As New SqlCommand("Select DocID From Doctors Where DocName LIKE #DocID", cs)
command.Parameters.AddWithValue("#DocID", AddFam.Doctor)
...

Sorting numbers in Access and .NET

I have an Access table which has a Number field and a Text field.
I can run a query like this:
SELECT * FROM Table ORDER BY intID ASC
//outputs 1,2,3,10
But when I try to run the same query through the .NET OleDB client, like this:
Private Sub GetData()
Using cnDB As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Path)
cnDB.Open()
Dim SQL As String = "SELECT * FROM Table ORDER BY intID ASC"
Dim cmd As New OleDbCommand(SQL, cnDB)
Dim dr As OleDbDataReader = cmd.ExecuteReader()
While dr.Read()
lst.Items.Add(dr.Item("intID") & " - " & dr.Item("strName"))
End While
cnDB.Close()
End Using
End Sub
I get items in the order 1,10,2,3.
What's going on here, and how can I have the data sort "naturally" (1,2,3,10) in both places?
try
SELECT * FROM Table ORDER BY CInt(intID) ASC
to explicitly tell Access to treat this as an integer and not a string. Obviously, something in the OleDbClient is seeing this field as a string (text field) and sorting accordingly.
I suspect the problem is your connection string. If you're connecting to an Access database and include IMEX=1 in your connection string, the provider will treat all data as string. As such, the ordering will order by the string value, giving you 1, 10, 2, 3, as opposed to leaving the intID as an integer, and ordering it in numerical order.
It looks like you're getting a lexical (alphabetic) order. This will be correct if something in your database or query thinks that is a varchar/text column type instead of a numeric type.