Insufficient parameters supplied to the command' in vb.net - vb.net

I am trying to do a SQL query that calculates the number of days between two dates from a database.
However an error occurs when I try to search for specific data from the database. Furthermore does anyone know how I could use the sql Query that counts how many days is between two dates in a calculation, which would use data from another table. I have a room type table which has a room price column, and a booking table where I have the arrival date and departure date how could I calculate the total price for the booking.
System.Data.SQLite.SQLiteException: 'unknown error
Insufficient parameters supplied to the command'
Here is what I have so far
Function GetDuration(ID As Integer, fname As String)
Dim dsql As String = "Select Cast ((
JulianDay(Replace(departuredate,'/','-'))
- JulianDay(Replace(arrivaldate,'/','-'))
) As Integer)
from booking INNER JOIN customers on customers.CustomerID = booking.BookingID
where booking.bookingid = #ID or customers.fname LIKE #Fname;"
Using con As New SQLiteConnection(ConStr)
Dim mycmd As New SQLiteCommand(dsql, con)
con.Open()
cmd.Parameters.Add("#Fname", DbType.String).Value = $"%{fname}%"
cmd.Parameters.Add("#ID", DbType.Int32).Value = ID
Dim value As Object = mycmd.ExecuteScalar()
txtdurationofstay = value
End Using
End Function
Private Sub IbtnSearch_Click(sender As Object, e As EventArgs) Handles ibtnBSearch.Click
If txtBookingSearchID.Text <> "" Then
Dim SearchID As Integer
If Int32.TryParse(txtBookingSearchID.Text, SearchID) Then
DgvBookings.DataSource = GetData("null", SearchID)
GetDuration(txtBookingSearchID.Text, "null")
Else
MessageBox.Show("Please enter a valid number in the Search box.")
End If
ElseIf txtBsearchFname.Text <> "" Then
DgvBookings.DataSource = GetData(txtBsearchFname.Text, 0)
GetDuration(0, txtBsearchFname.Text)
End If
End Sub

You defined mycmd here:
Dim mycmd As New SQLiteCommand(dsql, con)
but added the parameters to cmd and not to mycmd:
cmd.Parameters.Add("#Fname", DbType.String).Value = $"%{fname}%"
cmd.Parameters.Add("#ID", DbType.Int32).Value = ID
and then you execute:
mycmd.ExecuteScalar()
but there are no parameters in mycmd.

Related

Filter a row using a column from another data table

I have a (Household) table which have two columns: firstname and lastname. The second table (Complaints) also has two columns: respondents and remarks. Now im trying to check when the selected row in (household) has the same name values to the respondents column and has "UNSETTLED" value in remarks column. Then it will show household has records. If the value of respondents has a match but the remarks is = SETTLED then then the household has no records.
This is where to select the household
and when i select a row and click the button use selected
This form will open and the household has/no records, will show up in the black panel
I dont know what im doing wrong here so here's my code
Dim i As Integer
i = DataGridView1.CurrentRow.Index
Dim householdid = DataGridView1.Item(0, i).Value
Dim GLOBALid = DataGridView1.CurrentRow.Cells(0).Value
If con.State = ConnectionState.Closed Then
con.Open()
End If
Try
Dim command As New OleDbCommand("SELECT * FROM Household WHERE ID=#id", con)
Dim da As New OleDbDataAdapter(command)
With command
.Parameters.Add("#id", OleDb.OleDbType.VarChar).Value = GLOBALid
End With
command.ExecuteNonQuery()
Dim cmd1 As New OleDbCommand("SELECT count(*) FROM Complaint WHERE respondents LIKE '% #lastname %' OR respondents LIKE '% #firstname %' AND remarks=UNSETTLED ", con)
Dim da1 As New OleDbDataAdapter(cmd1)
With cmd1
.Parameters.Add("#lastname", OleDb.OleDbType.VarChar).Value = DataGridView1.Item(1, i).Value
.Parameters.Add("#firstname", OleDb.OleDbType.VarChar).Value = DataGridView1.Item(2, i).Value
End With
'Dim numrows As Integer = 0
'numrows = cmd.ExecuteScalar()
Dim rowcount = Convert.ToInt32(command.ExecuteScalar())
If rowcount >= 1 Then
BrgyclearanceWithRecords.Label17.ForeColor = Color.Red
BrgyclearanceWithRecords.Label17.Text = "Resident's Name has a match with an Existing unsettled complain!"
ElseIf rowcount = 0 Then
'BrgyclearanceWithRecords.Panel1.Visible = True
BrgyclearanceWithRecords.Label17.ForeColor = Color.Green
BrgyclearanceWithRecords.Label17.Text = "Resident's Name has no match with an Existing unsettled complain!"
End If
con.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
BrgyclearanceWithRecords.Show()
BrgyclearanceWithRecords.BringToFront()
End Sub
I don't guarantee it solves every problem but..
WHERE respondents LIKE '% #lastname %'
it doesn't work like this; that will literally just search for any rows where the respondents field contains the text " #lastname "
WHERE respondents LIKE #lastname
and if you want to put wildcards you put them in the value
Parameters.Add("#lastname", OleDb.OleDbType.VarChar).Value = "Smith%"
I would think your database should look something like this.
Where the ID in the Households table is the Primary Key and has a one to many relationship to the HouseholdID Foreign Key in the Complaints table.
I am guessing that DataGridView1 contains the Households and the first column contains the ID column.
The Using block includes the connection and the command. Both need to be disposed. End Using also closes the connection.
When you are using a literal string in the Where criteria, it needs to be surrounded by single quotes.
Since you are only retrieving a single value from the database you can use ExecuteScalar() which returns an Object, thus the CInt().
Once the connection is safetly closed and disposed with the End Using, you can check your returned value, count, and take the required actions.
Private OPConStr As String = "Your connection string."
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim count As Integer
Dim i = DataGridView1.CurrentRow.Index
Dim householdid = CInt(DataGridView1.Item(0, i).Value)
Try
Using con As New OleDbConnection(OPConStr),
cmd As New OleDbCommand("SELECT count(*) FROM Complaints WHERE HouseholdID = #ID AND Remarks = 'UNSETTLED';", con)
cmd.Parameters.Add("#id", OleDbType.Integer).Value = householdid
con.Open()
count = CInt(cmd.ExecuteScalar())
End Using
Catch ex As Exception
MessageBox.Show(ex.Message)
Exit Sub
End Try
If count >= 1 Then
BrgyclearanceWithRecords.Label17.ForeColor = Color.Red
BrgyclearanceWithRecords.Label17.Text = "Resident's Name has a match with an Existing unsettled complain!"
Else
BrgyclearanceWithRecords.Label17.ForeColor = Color.Green
BrgyclearanceWithRecords.Label17.Text = "Resident's Name has no match with an Existing unsettled complain!"
End If
BrgyclearanceWithRecords.Show()
BrgyclearanceWithRecords.BringToFront()
End Sub

Select from Service Based Database not finding any values without a selection in a DataGridView (WinFormsApp VB .Net Framework)

I'm quite new to VB .Net and Databases in general so I'm not sure which SQL Version I am using. I did most of my coding until now with VBA.
I added a "Service Based Database" to my "WinFormsApp" Project and created a Table with 3 Columns:
CREATE TABLE [dbo].[employees] (
[id] INT IDENTITY (1, 1) NOT NULL,
[nr] VARCHAR (MAX) NULL,
[name] TEXT NULL,
PRIMARY KEY CLUSTERED ([id] ASC)
);
Afterwards I added a Dataset for the created Table.
Following this, I added a new Form to my Project and added a few controls to it including two TextBoxes for Dataentry and a DataGridView to show the saved data. On Form_Load I fill the DataGridView using the following code:
Private Sub UpdateGridView()
'Loading the data into the GridView
'---------------------------------------
Dim Conn As SqlConnection = New SqlConnection
Dim ADP As SqlDataAdapter
Dim DS As DataSet = New DataSet
Conn.ConnectionString = My.Settings.DBConnEmployees
ADP = New SqlDataAdapter("SELECT * FROM employees", Conn)
ADP.Fill(DS)
Me.DataGridView_Employees.DataSource = DS.Tables(0)
'---------------------------------------
'Hidding the ID Col
Me.DataGridView_Employees.Columns(0).Visible = False
End Sub
Also in the Form_Load I set a few unrelated variables and TextBoxes (as I'm not able to find the errors after several hour of trial and error, I include this. Maybe I'm overlooking something):
Private Sub NewEmployee()
'Reseting the Variables
DataGridIndex = -1
EmployeeId = 0
EmployeeNr = String.Empty
EmployeeName = String.Empty
'Writing to TBs
Me.tbNr.Text = EmployeeNr
Me.tbName.Text = EmployeeName
'Select Nothing
Me.DataGridView_Employees.CurrentCell = Nothing
'Changing Btn Desc
Me.btnSaveEmployee.Text = "Neuen Mitarbeiter speichern"
End Sub
The testing data I entered into the table by hand fills in without a problem. Inserting, updating an deleting into/from the table by code works perfect.
On DataGrivView_CellDoubleClick I read some data of the the GridView into the TextBoxes to edit them:
Private Sub DataGridView_Employees_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView_Employees.CellDoubleClick
If e.RowIndex <> -1 Then
'Loading selected Data
DataGridIndex = e.RowIndex
EmployeeId = Me.DataGridView_Employees.Rows(DataGridIndex).Cells(0).Value
EmployeeNr = Me.DataGridView_Employees.Rows(DataGridIndex).Cells(1).Value
EmployeeName = Me.DataGridView_Employees.Rows(DataGridIndex).Cells(2).Value
'Write to TBs
Me.tbNr.Text = EmployeeNr
Me.tbName.Text = EmployeeName
'Changing btn
Me.btnSaveEmployee.Text = "Änderungen speichern"
End If
End Sub
To prevent the User from using the nr twice I wanted to check if the nr is already saved in the Table. However this is where the problems begin. The SQLCommand only finds the row which i double clicked in the GridView. Which is strange as there should be no connection between them. Hereafter my try at checking for the nr:
Private Function EmployeeNrInUse(id As Integer, nr As String) As Boolean
Dim Query As String = String.Empty
Dim Result
Dim Response As Boolean = True
'Checking for nr
'---------------------------------------
Query = "SELECT * FROM employees WHERE nr=#nr"
Using Conn = New SqlConnection(My.Settings.DBConnEmployees)
Using Comm = New SqlCommand()
With Comm
.Connection = Conn
.CommandType = CommandType.Text
.CommandText = Query
.Parameters.AddWithValue("#nr", nr)
End With
Try
Conn.Open()
Result = Comm.ExecuteScalar
Response = Not IsNothing(Result)
Catch ex As SqlException
MsgBox(ex.Message.ToString, vbOKOnly + vbCritical)
End Try
End Using
End Using
'---------------------------------------
'Return
Return Response
End Function
The Result is always returning nothing, unless I double clicked a dataentry before, then it finds it's own row (if the nr matches) but only that, no other matching nr is found.
If I forgot to mention crucial data, please inform me as this is my first question ever in a forum :) (Also please excuse any spelling mistakes etc. as English isn't my native language) Thanks in Advance for your help!
Edit:
This is how the Function EmployeeNrInUse is called (Called on Button_Clicked):
Private Sub SaveEmployeeToDB(id As Integer, nr As String, name As String)
Dim Query As String = String.Empty
'Adding new Employee / Editing existing
'---------------------------------------
If EmployeeNrInUse(id, nr) Then
MsgBox("Nr. bereits in verwendung.", vbOKOnly + vbExclamation)
Exit Sub
End If
If EmployeeId = 0 Then
Query = "INSERT INTO employees (nr, name) VALUES (#nr, #name)"
Else
Query = "UPDATE employees SET nr=#nr, name=#name WHERE id=#id"
End If
Using Conn As New SqlConnection(My.Settings.DBConnEmployees)
Using Comm As New SqlCommand()
With Comm
.Connection = Conn
.CommandType = CommandType.Text
.CommandText = Query
.Parameters.AddWithValue("#id", id) 'Wird nur bei änderung verwendet
.Parameters.AddWithValue("#nr", nr)
.Parameters.AddWithValue("#name", name)
End With
Try
Conn.Open()
Comm.ExecuteNonQuery()
UpdateGridView()
If EmployeeId = 0 Then
MsgBox("Neuen Mitarbeiter gespeichert.", vbOKOnly + vbInformation)
Else
MsgBox("Bestehenden Mitarbeiter aktualisiert.", vbOKOnly + vbInformation)
End If
NewEmployee()
Catch ex As SqlException
MsgBox(ex.Message.ToString, vbOKOnly + vbCritical)
End Try
End Using
End Using
'---------------------------------------
End Sub
The problem was caused by entering the values into the Database by hand. While copying the nr, a linebreak sneaked itself into the values so a check just for the nr instead the nr and the linebreak resulted in nothing. Properly entering the data has fixed the problem.

How to check and update existing record date when new row is entered else add new row

enter code hereSql table columns ( Clientid, Client_Status, Notes, Startdt,Enddt, Entrydt, Entryid) My current code adds data rows from UI, user enters Start date, Status and notes
with Enddt defaulting to 9/9/9999. I need to change my code to -whenever a new reord/Status is enrtered check for existing record/Status with that Clientid,
If records exists update the EndDt of existing record from 9/9/9999 to StartDt-1( new record StartDt) which is entered from Interface. Else enter as new client.
Private Sub BtnAddStatus_Click(sender As System.Object, e As System.EventArgs) Handles BtnAddStatus.Click
Clientid = txtboxClid.Text
Client_Status = cbboxStatus.Text
StartDt = txtStartDt.Text
notes = txtnote.Text
conn = New SqlClient.SqlConnection("conneting string")
Dim theQuery As String = "select * from Table name where Clientid = #Clientid and EndDt = '9/9/9999'"
Dim cmd2 As SqlCommand = New SqlCommand(theQuery, conn)
cmd2.Parameters.AddWithValue("#Clientid", txtboxClid.Text)
conn.Open()
If txtboxClid.Text.Trim <> "" And txtStartDt.Text.Trim <> "" Then
Using reader As SqlDataReader = cmd2.ExecuteReader()
If reader.HasRows Then
Dim query2 As String = "UPDATETable name SET ([EndDt] = SELECT (todate(StartDt)-1) FROM Table name WHERE Clientid = #Clientid and EndDt ='9/9/9999')"
reader.Close()
End If
End Using
Dim query As String = "INSERT INTO Table name (Clientid, Client_Status, Notes, Startdt,Enddt, Entrydt, Entryid) VALUES ('" & Clientid & "','" & Client_Status & "','" & Notes & "','" & StartDt & "',getdate(),'" & UName & "');"
Dim command = New SqlCommand(query, myconn)
command.ExecuteNonQuery()
MsgBox("Status Added ")
conn.Close()
Call GetInfoClientid()
End If
End If
End Sub
The simple reason is the fact that you are not executing the command stored in query2, but your code has other errors and someone potentially catastrophic.
First, you should always use parameters and never concatenate strings to build sql commands. If you concatenate strings you enable a simple trick called Sql Injection that allows anyone to hack your database.
Second you could directly call the Update without checking for the presence of a previous related record. The update will simply return with 0 record changed if the record doesn't exist.
Finally, the disposable objects like the connection should be created when needed and disposed as soon as possible. The Using Statement serves for this purpose.
Dim Client_Status As String = cbboxStatus.Text
Dim notes As String = txtnote.Text
' Suppose Clientid is a number not a string
Dim Clientid as Integer = Convert.ToInt32(txtboxClid.Text)
' Suppose you have a date in your database, not a string
Dim StartDt as DateTime = Convert.ToDateTime(txtStartDt.Text)
' Calculate here the previous ending date
Dim PrevEnd As DateTime = StartDt.AddDays(-1)
' Conventional max end date
Dim maxEndDate as DateTime = new DateTime(9999,9,9)
If txtboxClid.Text.Trim <> "" And txtStartDt.Text.Trim <> "" Then
' Create here the connection to dispose on exit from the using statement
Using conn As SqlConnection = New SqlClient.SqlConnection("conneting string")
conn.Open()
' USE PARAMETERS EVERYWHERE. DO NOT USE STRINGS TO FIND A DATE
Dim query2 As String = "UPDATE [Table name] SET [EndDt] = #newEnd
WHERE Clientid = #Clientid
AND EndDt = #maxEnd"
Dim command = New SqlCommand(query2, conn)
command.Parameters.Add("#Clientid", SqlDbType.Int).Value = Clientid
command.Parameters.Add("#newEnd", SqlDbType.Date).Value = newEnd
command.Parameters.Add("#maxEnd", SqlDbType.Date).Value = maxEndDate
command.ExecuteNonQuery()
' Prepare the insert.
Dim query As String = "INSERT INTO [Table name]
(Clientid, Client_Status, Notes, Startdt,Enddt, Entrydt, Entryid)
VALUES
(#Clientid, #status,#Notes,#StartDt,#maxDate,getdate(), #UName);"
command.Parameters.Clear()
command.Parameters.Add("#Clientid", SqlDbType.Int).Value = Clientid
command.Parameters.Add("#status", SqlDbType.NVarChar).Value = Client_Status
command.Parameters.Add("#notes", SqlDbType.NVarChar).Value = notes
command.Parameters.Add("#startdt", SqlDbType.Date).Value = StartDt
command.Parameters.Add("#maxDate", SqlDbType.Date).Value = maxEndDate
command.Parameters.Add("#uname", SqlDbType.NVarChar).Value = uname
command.CommandText = query
command.ExecuteNonQuery()
End Using
Call GetInfoClientid()
End If
Notice that I pass parameters of the appropriate type for what I suppose is the type of your columns. It is common error to think that a string like '9/9/9999' is a date. But for a computer program this is a string and if you want to use as a date we need to convert it to a proper date. This conversion more often than not results in wrong data passed to the database engine.
This should have been handled in stored procedure. But, since you have done most of the things here, I would suggest a minor change on this which would work. First, Remove the check before update and change the update query to:
Dim query2 As String = "UPDATE Table name SET [EndDt] = todate(#StartDt)-1 WHERE Clientid = #ClientId and EndDt ='9/9/9999'"
Dim cmd As SqlCommand = new SqlCommand(query2, vbConn);
cmd.AddParam(“#StartDt”,StartDt)
cmd.AddParam("#Clientid",ClientId)
(assuming clientid to be varchar, since you have used single quotes on insert statement)
Also, write executenonquery() statement for query2.

Compare entered date and database date

In a booking form, i want to compare the entered date in the textbox(text mode is date) and all the dates in the database. So if there is an order already booked on that day, it will display already booked select another date otherwise it will carry on the form filling.(in vb.net-visual studio 2012)
this is the code
Protected Sub tbdate_TextChanged(sender As Object, e As EventArgs) Handles tbdate.TextChanged
Dim adaptor As New SqlDataAdapter
Dim ds As New DataSet
Try
objConn.Open()
Dim sqlcmd As New SqlCommand("select order_date from bookorder where order_date=' " & tbdate.Text & "'", objConn)
sqlcmd.ExecuteNonQuery()
adaptor.SelectCommand = sqlcmd
adaptor.Fill(ds)
If ds.Tables(0).Rows.Count > 0 Then
Label8.Visible = True
Label8.Text = "Enter different date"
End If
adaptor.Dispose()
ds.Clear()
Catch
e.ToString()
Finally
objConn.Close()
End Try
End Sub
End Class
select * from table where CAST(datecolumn as DATE) = textbox.date
Maybe you have to cast your textbox's date in order to match DB's format...
Use DateTime.ParseExact method

Data type mismatch in criteria expression (vb.net, access)

I am trying to take data from the database to the grid. The condition is SELECT * FROM entries WHERE edate='" & Me.dtpDate.Value.Date & "'" But I am getting the error message Data type mismatch in criteria expression. Please see the code below. Also I have attached a screenshot of the error message.
Private Sub dtpDate_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles dtpDate.Leave
'GetDayBookOpeningBalance()
If Me.lblHeading1.Text <> "Daybook entry" Then
Using MyConnection As OleDb.OleDbConnection = FrmCommonCodes.GetConnection(),
MyAdapter As New OleDb.OleDbDataAdapter("SELECT * FROM entries WHERE edate='" & Me.dtpDate.Value.Date & "'", MyConnection)
'Format(Me.dtpDate.Value.Date, "dd/MM/yyyy"))
If MyConnection.State = ConnectionState.Closed Then MyConnection.Open()
Using MyDataSet As New DataSet
MyAdapter.Fill(MyDataSet, "entries")
Me.grdDayBook.DataSource = MyDataSet.Tables("entries")
Dim DataSetRowCount As Integer = MyDataSet.Tables("entries").Rows.Count
If DataSetRowCount > 0 Then
SetGridProperty()
Else
ShowBlankGrid()
FrmCommonCodes.MessageDataNotFound()
End If
End Using
End Using
Else
ShowBlankGrid()
End If
End Sub
This is exactly what could happen for not using parameterized queries.
I bet that your column edate is a column of type Date/Time but you concatenate your Me.dtpDate.Value.Date to the remainder of your sql string command.
This forces an automatic conversion from DateTime to String but the conversion is not as your database would like to see.
If you use a parameter there is no conversion and the database engine understand exactly what you are passing.
Dim sqlText = "SELECT * FROM entries WHERE edate=#dt"
MyAdapter As New OleDb.OleDbDataAdapter(sqlText, MyConnection)
MyAdapter.SelectCommand.Parameters.Add("#dt", OleDbType.Date).Value = Me.dtpDate.Value.Date
....