Failed to convert parameter value from a string to int32 - vb.net

cmd1.CommandText = "insert into tblInvoiceDetails (InvoiceNo)values(#InvoiceNo )"
With cmd1.Parameters
.AddWithValue("#InvoiceNo", NumericUpDown1.Value)
cmd1.CommandText = "insert into tblInvoiceDetails (itemno,ItemName,Qt,Price,Total)values(#itemno,#ItemName,#Qt,#Price,#Total)"
'cmd1.Parameters.Add("#InvoiceNo", NumericUpDown1 .Value )
cmd1.Parameters.Add("#itemno", SqlDbType.Int)
cmd1.Parameters.Add("#ItemName", SqlDbType.VarChar)
cmd1.Parameters.Add("#Qt", SqlDbType.Int)
cmd1.Parameters.Add("#Price", SqlDbType.Money)
cmd1.Parameters.Add("#Total", SqlDbType.Money)
For x As Integer = 0 To DataGridView2.RowCount - 1
cmd1.Parameters(0).Value = DataGridView2.Rows(x).Cells(0).Value
cmd1.Parameters(1).Value = DataGridView2.Rows(x).Cells(1).Value
cmd1.Parameters(2).Value = DataGridView2.Rows(x).Cells(2).Value
cmd1.Parameters(3).Value = DataGridView2.Rows(x).Cells(3).Value
cmd1.Parameters(4).Value = DataGridView2.Rows(x).Cells(4).Value
Next
End With
cmd1.ExecuteNonQuery()
cmd1.Parameters.Clear()

It looks like you are inserting several values from a DataGridView into the database, and they all have the same InvoiceNo.
To make it easier to see which parameter is which, you can refer to them by the parameter name.
To make sure that the data types are correct, use the various Convert functions.
You would need to execute the query for each row of data. There is no need to clear the parameters, just change the value of each one.
So your code would end up something like:
Dim sql = "INSERT INTO tblInvoiceDetails ([itemno], [ItemName], [Qt], [Price], [Total]) VALUES (#itemno, #ItemName, #Qt, #Price, #Total)"
Using conn As New SqlConnection("your connection string"),
cmd1 As New SqlCommand(sql, conn)
cmd1.Parameters.Add("#InvoiceNo", SqlDbType.Int)
cmd1.Parameters.Add("#itemno", SqlDbType.Int)
'TODO: Use the correct size for the VARCHAR column:
cmd1.Parameters.Add("#ItemName", SqlDbType.VarChar, 128)
cmd1.Parameters.Add("#Qt", SqlDbType.Int)
cmd1.Parameters.Add("#Price", SqlDbType.Money)
cmd1.Parameters.Add("#Total", SqlDbType.Money)
cmd1.Parameters("#InvoiceNo").Value = Convert.ToInt32(NumericUpDown1.Value)
conn.Open()
For x As Integer = 0 To DataGridView2.RowCount - 1
cmd1.Parameters("#itemno").Value = Convert.ToInt32(DataGridView2.Rows(x).Cells(0).Value)
cmd1.Parameters("#ItemName").Value = Convert.ToString(DataGridView2.Rows(x).Cells(1).Value)
cmd1.Parameters("#Qt").Value = Convert.ToInt32(DataGridView2.Rows(x).Cells(2).Value)
cmd1.Parameters("#Price").Value = Convert.ToDecimal(DataGridView2.Rows(x).Cells(3).Value)
cmd1.Parameters("#Total").Value = Convert.ToDecimal(DataGridView2.Rows(x).Cells(4).Value)
cmd1.ExecuteNonQuery()
Next
End Using
The Using Statement takes care of cleaning up unmanaged resources used by the SqlConnection and SqlCommand.
When you have a string parameter (#ItemName in this case), it is best to tell it the size of the column in the database. I guessed at 128, but you should put in the actual value.
Also, you really should give the controls meaningful names, for example "InvoiceNoSelector" instead of "NumericUpDown1".

Related

System.IndexOutOfRangeException: while inserting data to mdf database file

Im getting this error while inserting data to my mdf database file
System.IndexOutOfRangeException: 'An SqlParameter with ParameterName '#qtysold' is not contained by this SqlParameterCollection.'
This is my code for order function
Function order(ByVal cart As List(Of Integer), ByVal product_qty As List(Of Integer))
If con.State = ConnectionState.Open Then
con.Close()
End If
con.Open()
'INSERT INTO PRODUCT TABLE
cmd.CommandType = CommandType.Text
cmd.CommandText = "UPDATE product SET product_qty= product_qty - #qty WHERE product_id= #id"
cmd.Parameters.Add("#qty", SqlDbType.Int)
cmd.Parameters.Add("#id", SqlDbType.Int)
For i As Integer = 0 To cart.Count - 1
cmd.Parameters("#id").Value = cart(i)
cmd.Parameters("#qty").Value = product_qty(i)
cmd.ExecuteNonQuery()
Next
'INSERT INTO SALES TABLE
cmd.CommandType = CommandType.Text
cmd.CommandText = "INSERT INTO sales VALUES (#id, #productname, #qtysold, #date)"
cmd.Parameters.Add("#id", SqlDbType.Int)
cmd.Parameters.Add("#productname", SqlDbType.VarChar)
cmd.Parameters.Add("#qtysold", SqlDbType.Int)
cmd.Parameters.Add("#date", SqlDbType.Date)
For i As Integer = 0 To cart.Count - 1
cmd.Parameters("#id").Value = cart(i)
cmd.Parameters("#productname").Value = getName(cart(i))
cmd.Parameters("#qtysold").Value = product_qty(i)
cmd.Parameters("#date").Value = datefield.Text
cmd.ExecuteNonQuery()
Next
cart.Clear()
product_qty.Clear()
refresh()
End Function
THE ERROR HAPPENS HERE
cmd.Parameters("#qtysold").Value = product_qty(i)
That seems an odd exception in that situation as the code looks OK to me but it's wrong even if it did work. Don't add the parameters and then get them back by name over and over. The Add method you're calling returns the SqlParameter object added so assign it to a variable and then use that:
Dim idParameter = cmd.Parameters.Add("#id", SqlDbType.Int)
Dim productionNameParameter = cmd.Parameters.Add("#productname", SqlDbType.VarChar)
Dim qtySoldParameter = cmd.Parameters.Add("#qtysold", SqlDbType.Int)
Dim dateParameter = cmd.Parameters.Add("#date", SqlDbType.Date)
For i As Integer = 0 To cart.Count - 1
idParameter.Value = cart(i)
productionNameParameter.Value = getName(cart(i))
qtySoldParameter.Value = product_qty(i)
dateParameter.Value = datefield.Text
cmd.ExecuteNonQuery()
Next
NEVER use the same complex expression over and over. ALWAYS use it once and assign the result to a variable, then use that variable over and over. In this case, you don't even have to use the complex expression once, because you already had the object but just ignored it.

How to execute query and store data of a column in a variable in VB.net?

I have the following code where I am trying to execute a query and store the value from the database in two variables. Depending on the variables, I would like to tick a checkbox and add some text to a textbox.
Here is the code:
Try
Dim cn As SqlConnection
Dim strCnn As String = ConfigurationManager.ConnectionStrings("agilityconnectionstring").ConnectionString
cn = New SqlConnection(strCnn)
cn.Open()
Dim comm As New SqlCommand("select IsCompleted, CompletionDate from managerchecklist where ID = 53 and QuestionID = 1", cn)
comm.CommandType = CommandType.Text
Dim ds As SqlDataReader
ds = comm.ExecuteReader()
If ds.HasRows Then
While ds.Read
IsComplete = ds.Item("IsCompleted").ToString()
CompleteDate = ds.Item("CompletionDate").ToString()
identifytasks_done.Checked = True
identifytasks_date.Attributes.Add("style", "display:block")
identifytasks_date.Text = CompleteDate
End While
End If
''Close your connections and commands.
cn.Close()
Catch ex As Exception
''Handle error if any
End Try
But I seem to be going wrong somewhere. Can anyone please help me?
Depending on the variables, I would like to tick a checkbox and add some text to a textbox.
Have an If Statement to check the variables whether it is complete
If IsComplete = "complete" Then
identifytasks_done.Checked = True
identifytasks_date.Attributes.Add("style", "display:block")
identifytasks_date.Text = CompleteDate
End If
Move the checking to SQL statement
Dim comm As New SqlCommand(
"select IsCompleted, CompletionDate from " +
"managerchecklist where ID = 53 and QuestionID = 1 and "
"IsCompleted = 'complete'",
cn)
Consider using parameter SQL instead to prevent SQL injection
I would recommend a Using statement for SQL queries and also parameters.
Get the values from SQL then use an IF statement to do whatever based on the values.
Assuming IsCompleted is a bit field in SQL....
Dim isCompleted As Boolean
Dim completedDate As Date
Using con As New SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("agilityconnectionstring").ConnectionString)
Using cmd As New SqlClient.SqlCommand("SELECT [IsCompleted], [CompletionDate] FROM managerchecklist where [ID] = #managerchecklistID and [QuestionID] = #questionID", con)
cmd.Parameters.Add("#managerchecklistID", SqlDbType.Int).Value = 53
cmd.Parameters.Add("#questionID", SqlDbType.Int).Value = 1
con.Open()
Using reader As SqlClient.SqlDataReader = cmd.ExecuteReader
While reader.Read
'Index in order of the columns in the SELECT statement
If reader.GetSqlBoolean(0).IsNull = False Then isCompleted = reader.GetSqlBoolean(0)
If reader.GetSqlDateTime(1).IsNull = False Then completedDate = reader.GetSqlDateTime(1)
End While
End Using
End Using
End Using
If isCompleted Then
identifytasks_done.Checked = True
identifytasks_date.Attributes.Add("style", "display:block")
identifytasks_date.Text = completedDate
End If
You could place this in a Sub of it's own with managerchecklistID and questionID as arguments then set the parameter values with the arguments
cmd.Parameters.Add("#managerchecklistID", SqlDbType.Int).Value = managerchecklistID
cmd.Parameters.Add("#questionID", SqlDbType.Int).Value = questionID

if the input value is in between two values then display the result

I have a SQL table with three columns "From","To" and "Equivalent Value". Each value is shown below:
From To Equivalent Value
1,001.00 2,000.00 200.00
2,001.00 3,000.00 300.00
Now if the user enters the value "1,200.00" in textbox1 it will display the result value to textbox2 which is "200.00" because that is the corresponding value of between "From" and "To.
Another condition, if the user enters the value "2,500.00" in textbox1 it will display the value "300.00".
So far, I have tried this code but no luck:
Dim conn As SqlConnection = SQLConn()
Dim da As New SqlDataAdapter
Dim dt As New DataTable
conn.Open()
Dim cmd As New SqlCommand("", conn)
Dim result As String
cmd.CommandText = "SELECT [Equivalent Value] FROM tblSSS"
result = IIf(IsDBNull(cmd.ExecuteScalar), "", cmd.ExecuteScalar)
da.SelectCommand = cmd
dt.Clear()
da.Fill(dt)
If result <> "" Then
If TextBox1.Text >= dt.Rows(0)(1).ToString() And TextBox1.Text <= dt.Rows(0)(2).ToString() Then
TextBox2.Text = dt.Rows(0)(3).ToString()
End If
End If
If I have got this right I think there are a couple of things I would change which may help you:
Use Using. This will dispose of the SQL objects once finished with.
Use SqlParameters. This will help with filtering your data.
Remove the use of SqlDataAdapter. In this case I don't feel it's needed.
The use of IIf. I will be using If which has replaced IIf.
With these in mind I would look at something like this:
Dim fromValue As Decimal = 0D
Dim toValue As Decimal = 0D
If Decimal.TryParse(TextBox1.Text, fromValue) AndAlso Decimal.TryParse(TextBox1.Text, toValue) Then
Dim dt As New DataTable
Using conn As SqlConnection = SQLConn,
cmd As New SqlCommand("SELECT [Equivalent Value] FROM tblSSS WHERE [From] >= #From AND [To] <= #To", conn)
cmd.Parameters.Add(New SqlParameter With {.ParameterName = "#From", .SqlDbType = SqlDbType.Decimal, .Value = fromValue})
cmd.Parameters.Add(New SqlParameter With {.ParameterName = "#To", .SqlDbType = SqlDbType.Decimal, .Value = toValue})
conn.Open()
dt.Load(cmd.ExecuteReader)
End Using
If dt.Rows.Count = 1 Then
TextBox2.Text = If(IsDBNull(dt.Rows(0).Item("Equivalent Value")), "0", dt.Rows(0).Item("Equivalent Value").ToString)
End If
End If
Note the use of Decimal.TryParse:
Converts the string representation of a number to its Decimal equivalent. A return value indicates whether the conversion succeeded or failed.
This is an assumption that the From and To fields in your database are Decimal.
Now to explain the difference between IIf and If. IIf executes each portion of the statement even if it's true whilst If executes only one portion. I won't go into detail as many others on here have done that already. Have a look at this answer.
As per Andrew Morton's comment and more in line with what the OP attempted here is a solution that uses ExecuteScaler.
ExecuteScaler executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.
With this in mind:
'I reset the value of TextBox2.Text. You may not want to.
TextBox2.Text = ""
Dim fromValue As Decimal = 0D
Dim toValue As Decimal = 0D
If Decimal.TryParse(TextBox1.Text, fromValue) AndAlso Decimal.TryParse(TextBox1.Text, toValue) Then
Using conn As SqlConnection = SQLConn,
cmd As New SqlCommand("SELECT [Equivalent Value] FROM tblSSS WHERE [From] >= #From AND [To] <= #To", conn)
cmd.Parameters.Add(New SqlParameter With {.ParameterName = "#From", .SqlDbType = SqlDbType.Decimal, .Value = fromValue})
cmd.Parameters.Add(New SqlParameter With {.ParameterName = "#To", .SqlDbType = SqlDbType.Decimal, .Value = toValue})
conn.Open()
Try
TextBox2.Text = cmd.ExecuteScalar().ToString()
Catch ex As Exception
End Try
End Using
End If
I have used the example on the ExecuteScaler MSDN documentation. You might want to look into handling the exception on the Try Catch a little better and not letting it go to waste.
You may want to place this code on the TextBox1.Leave method or maybe on a Button.Click method. That's totally up to you.
There may a few changes you may need to make however I think this will give you a few ideas on how to move ahead with your code.
Hope it Helps...
Dim connetionString As String
Dim cnn As SqlConnection
Dim cmd As SqlCommand
Dim sql As String
connetionString = "Data Source=ServerName;Initial Catalog=DatabaseName;User ID=UserName;Password=Password"
sql = "SELECT [Equivalent Value] FROM tblSSS WHERE [FROM]<=" & Val(TextBox1.Text) & " AND [TO]>= " & Val(TextBox1.Text)
cnn = New SqlConnection(connetionString)
Try
cnn.Open()
cmd = New SqlCommand(sql, cnn)
Dim count As Int32 = Convert.ToInt32(cmd.ExecuteScalar())
cmd.Dispose()
cnn.Close()
Catch ex As Exception
MsgBox("Can not open connection ! ")
End Try

How can I read a specific column in a database?

I hava a Table named DTR_Table it has 8 columns in it namely:
EmployeeID,Date,MorningTime-In,MorningTime-Out,AfternoonTime-In,AfternoonTime-Out,UnderTime,Time-Rendered.I want to read the column "AfternoonTime-In".
Following is my code. It reads my "AfternoonTime-In" field, but it keeps on displaying "Has Rows" even if there is nothing in that column.
How can I fix this?
Connect = New SqlConnection(ConnectionString)
Connect.Open()
Dim Query1 As String = "Select [AfternoonTime-Out] From Table_DTR Where Date = #Date and EmployeeID = #EmpID "
Dim cmd1 As SqlCommand = New SqlCommand(Query1, Connect)
cmd1.Parameters.AddWithValue("#Date", DTRform.datetoday.Text)
cmd1.Parameters.AddWithValue("#EmpID", DTRform.DTRempID.Text)
Using Reader As SqlDataReader = cmd1.ExecuteReader()
If Reader.HasRows Then
MsgBox("Has rows")
Reader.Close()
Else
MsgBox("empty")
End If
End Using`
After returning the DataReader you need to start reading from it if you want to extract values from your query.
Dim dt = Convert.ToDateTime(DTRform.datetoday.Text)
Dim id = Convert.ToInt32(DTRform.DTRempID.Text)
Using Connect = New SqlConnection(ConnectionString)
Connect.Open()
Dim Query1 As String = "Select [AfternoonTime-Out] From Table_DTR
Where Date = #Date and EmployeeID = #EmpID"
Dim cmd1 As SqlCommand = New SqlCommand(Query1, Connect)
cmd1.Parameters.Add("#Date", SqlDbType.DateTime).Value = dt
cmd1.Parameters.Add("#EmpID", SqlDbType.Int).Value = id
Using Reader As SqlDataReader = cmd1.ExecuteReader()
While Reader.Read()
MessageBox.Show(Reader("AfternoonTime-Out").ToString())
Loop
End Using
End Using
Note that I have changed the AddWithValue with a more precise Add specifying the parameter type. Otherwise, your code will be in the hand of whatever conversion rules the database engine decides to use to transform the string passed to AddWithValue to a DateTime.
It is quite common for this conversion to produce invalid values especially with dates

vb.net SQL causing - "Must declare the scalar variable "

I've been stuck on this error for a while, in vb.net trying to connect to SQL and pull data from a table within a day, using parameters to do this, a datetimepicker - the data saved to SQL is in a custom datetime format dd/MM/yyyy HH:mm:ss,
When i execute my code i get
"Must declare the scalar variable "#line"
When i remove the code " WHERE [line] = #line and date >= #startdata AND date < #enddata " it works but shows all the data without the date range as it should.
connect()
DataGridView1.AutoGenerateColumns = True
cmd.Parameters.Clear()
cmd.CommandText = #"SELECT board, defect, date, detail_x, detail_y,
detail_width, detail_height
FROM [sqlccmdefects]
WHERE [line] = #line
and date >= #startdata
AND date < #enddata";
cmd.Parameters.Add("#line", SqlDbType.VarChar, 30).Value = Form1.line.Text
cmd.Parameters.Add("#startdata", SqlDbType.DateTime).Value = DateTimePicker1.Value
cmd.Parameters.Add("#enddata", SqlDbType.DateTime).Value = DateTimePicker2.Value
cmd.ExecuteScalar()
Dim dataAdapter1 = New SqlDataAdapter(cmd.CommandText, con.ConnectionString)
Dim table1 As New DataTable()
table1.Locale = System.Globalization.CultureInfo.InvariantCulture
dataAdapter1.Fill(table1)
Me.BindingSource1.DataSource = table1
DataGridView1.DataSource = BindingSource1
disconnect()
All i get is a blank Datagridview with the scalar error.
There looks to be a couple of issues in the code you posted,
Try this:
'SQL Connection
Dim sqlCon As New SqlConnection("Server=.;Database=dummy;Trusted_Connection=True;")
'SQL Command
Dim sqlCmd As New SqlCommand("", sqlCon)
sqlCmd.CommandText = "SELECT board, defect, date, detail_x, detail_y, detail_width, detail_height FROM [sqlccmdefects] WHERE [line] = #line and date >= #startdata AND date < #enddata"
'SQL Command Params
sqlCmd.Parameters.Add("#line", SqlDbType.VarChar, 30).Value = "WHATEVER"
sqlCmd.Parameters.Add("#startdata", SqlDbType.DateTime).Value = "2015-07-21"
sqlCmd.Parameters.Add("#enddata", SqlDbType.DateTime).Value = "2015-07-23"
'Data Adapters
Dim dataAdapter1 = New SqlDataAdapter(sqlCmd)
Dim table1 As New DataTable()
'NOT SURE WHAT THIS DOES?
table1.Locale = System.Globalization.CultureInfo.InvariantCulture
'Attach to the GV
dataAdapter1.Fill(table1)
DataGridView1.AutoGenerateColumns = True
BindingSource1.DataSource = table1
DataGridView1.DataSource = BindingSource1
ExecuteScalar is typically used when your query returns a single value. If it returns more, then the result is the first column of the first row.
Use cmd.ExecuteReader() or cmd.ExecuteNonQuery() instead of cmd.ExecuteScalar()
cmd.ExecuteScalar()
will execute the command – consuming the parameters – and throwing away any result (use ExecuteNonQuery when there is no result: saves setting up to return values).
When you fill the data adapter the command will be run again. But this time there are no parameters, and SQL fails on the first undefined identifier.
So: don't execute the command, instead pass the (unexecuted) command to the (single argument) data adapter constructor.