Multiple if statements, then, or else? - sql

I'm having some problems getting a query to run based off another query. Here's the database diagram to give a little background. The primary keys for all the tables are automatically generated by identites. The first 2 insert statements (Donation and Food_Donation) work but I can't get the last insert into Donation_Details to work. Here's the code so far:
Dim con As New OleDbConnection(DBcon)
Try
Dim dr As OleDbDataReader
Dim command As New OleDbCommand("Insert into Donation (Donor_ID) VALUES ( " & txtDonNum.Text & "); Select ##Identity;")
con.Open()
command.Connection = con
dr = command.ExecuteReader
Dim Donation_ID As String = ""
If dr.Read() Then
Donation_ID = dr(0).ToString
Dim food As New OleDbCommand("Insert into Food_Donation (Date_Received, Donation_ID) Values ( '" & maskedreceived.Text & "', " & Donation_ID & "); Select ##Identity")
food.Connection = con
food.ExecuteNonQuery()
End If
Dim Food_ID As String = ""
If dr.Read() Then
Food_ID = dr(0).ToString
Dim food2 As New OleDbCommand("Insert into Donation_Details (Quantity, Unit, Expiration_Date, Food_ID, Storage_ID, Type_ID) Values ( " & txtQuantity.Text & ", '" & boxUnit.Text & "', '" & maskedexpire.Text & "', " & Food_ID & ", " & txtStorageID.Text & ", " & txtTypeID.Text & ")")
food2.Connection = con
food2.ExecuteNonQuery()
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
con.Close()
End Try
End sub
I'm fairly correct my SQL statements are correct and it's just whether or not the last statements need to be an If or something else.

You should be using dr = food.ExecuteReader() rather than food.ExecuteNonQuery() if you want to reuse dr to acquire Food_ID?

I suspect your problem is that you're using If dr.Read() twice.
The dr.Read() method will move the reader forward to the next row but you are only selecting a single value in your initial query.
So, for example, your reader (being made from the insert) will return a single row value for the successful insert. Calling Read() on it will succeed but then move the row cursor to EOF causing subsequent Read() calls to return FALSE

Related

MysqlDataReader.Read stuck on the last record and doesnt EOF

i confused why mySqlDataReader.Read stuck on the last record and doesnt EOF ..
Here's my private function for executeSql :
Private Function executeSQL(ByVal str As String, ByVal connString As String, ByVal returnRecordSet As Boolean) As Object
Dim cmd As Object
Dim objConn As Object
Try
If dbType = 2 Then
cmd = New MySqlCommand
objConn = New MySqlConnection(connString)
Else
cmd = New OleDbCommand
objConn = New OleDbConnection(connString)
End If
'If objConn.State = ConnectionState.Open Then objConn.Close()
objConn.Open()
cmd.Connection = objConn
cmd.CommandType = CommandType.Text
cmd.CommandText = str
If returnRecordSet Then
executeSQL = cmd.ExecuteReader()
executeSQL.Read()
Else
cmd.ExecuteNonQuery()
executeSQL = Nothing
End If
Catch ex As Exception
MsgBox(Err.Description & " #ExecuteSQL", MsgBoxStyle.Critical, "ExecuteSQL")
End Try
End Function
And this is my sub to call it where the error occurs :
Using admsDB As MySqlConnection = New MySqlConnection("server=" & rs("server") & ";uid=" & rs("user") & ";password=" & rs("pwd") & ";port=" & rs("port") & ";database=adms_db;")
admsDB.Open()
connDef.Close()
rs.Close()
'get record on admsdb
Dim logDate As DateTime
Dim str As String
str = "select userid, checktime from adms_db.checkinout in_out where userid not in (select userid " &
"from adms_db.checkinout in_out join (select str_to_date(datetime,'%d/%m/%Y %H:%i:%s') tgl, fid from zsoft_bkd_padang.ta_log) ta " &
"on ta.fid=userid and tgl=checktime)"
Dim rsAdms As MySqlDataReader = executeSQL(str, admsDB.ConnectionString, True)
Dim i As Integer
'This is where the error is, datareader stuck on the last record and doesnt EOF
While rsAdms.HasRows
'i = i + 1
logDate = rsAdms(1)
'save to ta_log
str = "insert into ta_log (fid, Tanggal_Log, jam_Log, Datetime) values ('" & rsAdms(0) & "','" & Format(logDate.Date, "dd/MM/yyyy") & "', '" & logDate.ToString("hh:mm:ss") & "', '" & logDate & "')"
executeSQL(str, oConn.ConnectionString, False)
rsAdms.Read()
End While
'del record on admsdb
str = "truncate table checkinout"
executeSQL(str, admsDB.ConnectionString, False)
End Using
i'm new to vbnet and really have a little knowledge about it,, please help me,, and thank you in advance..
The issue is that you're using the HasRows property as your loop termination expression. The value of that property never changes. Either the reader has rows or it doesn't. It's not a check of whether it has rows left to read, so reading has no effect.
You are supposed to use the Read method as your flag. The data reader begins without a row loaded. Each time you call Read, it will load the next row and return True or, if there are no more rows to read, it returns False.
You normally only use HasRows if you want to do something special when the result set is empty, e.g.
If myDataReader.HasRows Then
'...
Else
MessageBox.Show("No matches found")
End If
If you don't want to treat an empty result set as a special case then simply call Read:
While myDataReader.Read()
Dim firstFieldValue = myDataReader(0)
'...
End While
Note that trying to access any data before calling Read will throw an exception.

how to save all record show in datagridview to the database

i have this code that will save only the top row of the datagridview,
can someone help me to modify this code so that it will save all the row in datagridview. im using vb 2010 and my database is ms access. thankyou in advance.
Try
Dim cnn As New OleDbConnection(conString)
query = "Insert into tblreportlog(EmpID,empname,department,empdate,timeinaM,timeoutam,lateam,timeinpm,timeoutpm,latepm,thw) values ('" & dgvReport.Item(0, dgvReport.CurrentRow.Index).Value & "', '" & dgvReport.Item(1, dgvReport.CurrentRow.Index).Value & "', '" & dgvReport.Item(2, dgvReport.CurrentRow.Index).Value & "','" & dgvReport.Item(3, dgvReport.CurrentRow.Index).Value & "','" & dgvReport.Item(4, dgvReport.CurrentRow.Index).Value & "','" & dgvReport.Item(5, dgvReport.CurrentRow.Index).Value & "','" & dgvReport.Item(6, dgvReport.CurrentRow.Index).Value & "','" & dgvReport.Item(7, dgvReport.CurrentRow.Index).Value & "', '" & dgvReport.Item(8, dgvReport.CurrentRow.Index).Value & "','" & dgvReport.Item(9, dgvReport.CurrentRow.Index).Value & "','" & dgvReport.Item(10, dgvReport.CurrentRow.Index).Value & "')"
cmd = New OleDbCommand(query, cnn)
cnn.Open()
cmd.ExecuteNonQuery()
cnn.Close()
Catch ex As Exception
MsgBox("ERROR: " & ErrorToString(), MsgBoxStyle.Critical)
End Try
Working from what is shown and best practices injected, you should be working from a data source such as a DataTable e.g. if when presented the DataGridView to the user there are no rows then create a new DataTable, set the DataTable as the DataSource of the DataGridView then when you are ready to save these rows in the DataGridView cast the DataSource of the DataGridView to a DataTable and use logic similar to the following
Dim dt As DataTable = CType(DataGridView1.DataSource, DataTable)
If dt.Rows.Count > 0 Then
Using cn As New OleDb.OleDbConnection With {.ConnectionString = "Your connection string"}
' part field list done here
Using cmd As New OleDb.OleDbCommand With
{
.Connection = cn,
.CommandText = "Insert into tblreportlog(EmpID,empname,department) values (#EmpID,#empname,#department)"
}
' TODO - field names, field types
cmd.Parameters.AddRange(
{
{New OleDb.OleDbParameter With {.ParameterName = "#EmpID", .DbType = DbType.Int32}},
{New OleDb.OleDbParameter With {.ParameterName = "#empname", .DbType = DbType.Int32}},
{New OleDb.OleDbParameter With {.ParameterName = "#department", .DbType = DbType.String}}
}
)
Dim Affected As Integer = 0
cn.Open()
Try
For Each row As DataRow In dt.Rows
' this should not be a auto-incrementing key
cmd.Parameters("#EmpID").Value = row.Field(Of Integer)("FieldName goes here")
cmd.Parameters("#empname").Value = row.Field(Of Integer)("FieldName goes here")
cmd.Parameters("#department").Value = row.Field(Of String)("FieldName goes here")
Affected = cmd.ExecuteNonQuery
If Affected <> 1 Then
Console.WriteLine("Error message, insert failed")
End If
Next
Catch ex As Exception
'
' handle exception
'
' for now
MessageBox.Show("Failed with: " & ex.Message)
' decide to continue or not
End Try
End Using
End Using
End If
On the other hand, if there are new rows with current rows we cast the data source as above then check for new rows along with validation as needed.
For Each row As DataRow In dt.Rows
If row.RowState = DataRowState.Added Then
If Not String.IsNullOrWhiteSpace(row.Field(Of String)("CompanyName")) Then
Other options, utilize a DataAdapter or setup data via data wizards in the ide where a BindingNavigator is setup with a save button.
If it's important to get the new primary key back the method for all methods can do this too.
The following code sample is from this MSDN code sample that shows how to get a new key back using OleDb connection and command.
Public Function AddNewRow(ByVal CompanyName As String, ByVal ContactName As String, ByVal ContactTitle As String, ByRef Identfier As Integer) As Boolean
Dim Success As Boolean = True
Try
Using cn As New OleDb.OleDbConnection(Builder.ConnectionString)
Using cmd As New OleDb.OleDbCommand("", cn)
cmd.CommandText = "INSERT INTO Customer (CompanyName,ContactName,ContactTitle) Values (#CompanyName,#ContactName,#ContactTitle)"
cmd.Parameters.AddWithValue("#CompanyName", CompanyName.Trim)
cmd.Parameters.AddWithValue("#ContactName", ContactName.Trim)
cmd.Parameters.AddWithValue("#ContactTitle", ContactTitle.Trim)
cn.Open()
cmd.ExecuteNonQuery()
cmd.CommandText = "Select ##Identity"
Identfier = CInt(cmd.ExecuteScalar)
End Using
End Using
Catch ex As Exception
Success = False
End Try
Return Success
End Function

data is not inserted to database

i tried to insert the data into database with this code
Public Sub AddUser()
Dim con As dbConn = New dbConn()
Dim SqlSelect As String
SqlSelect = "SELECT * FROM login Where user_id='" & WorkerID_.Text & "'"
Dim cmd As New OleDbCommand(SqlSelect, con.oleconnection)
Dim reader As OleDbDataReader
Dim da As New OleDbDataAdapter
con.open()
reader = cmd.ExecuteReader()
reader.Read()
If reader.HasRows() Then
reader.Close()
con.close()
FailureText.Text = "User ID already exists!"
Else
reader.Close()
con.close()
Dim InsertSQL As String
InsertSQL = "INSERT INTO login (user_id, user_role, user_password, user_status) VALUES "
InsertSQL &= "('" & WorkerID_.Text & "', "
InsertSQL &= "'Worker', "
InsertSQL &= "'12345', 1)"
Dim SqlUpdate As String
SqlUpdate = "INSERT INTO Worker (ID, WorkerID, WorkerName, DoB, Address, Phone, Email, CompanyName, PassportNum, PassportExp, VisaExp, VisaStatus, user_id) VALUES (default,"
SqlUpdate &= "'" & WorkerID_.Text & "', "
SqlUpdate &= "'" & WorkerName.Text & "', "
SqlUpdate &= "'" & DoB.Text & "', "
SqlUpdate &= "'" & Address.Text & "', "
SqlUpdate &= "'" & Phone.Text & "', "
SqlUpdate &= "'" & Email.Text & "', "
SqlUpdate &= "'" & Company.SelectedValue & "', "
SqlUpdate &= "'" & PassNum.Text & "', "
SqlUpdate &= "'" & PassExp.Text & "', "
SqlUpdate &= "'" & VisaExp.Text & "', "
SqlUpdate &= "'No Visa', "
SqlUpdate &= "'" & WorkerID_.Text & "') "
Dim insertCommand As New OleDbCommand(SqlUpdate, con.oleconnection)
Dim cmd1 As New OleDbCommand(InsertSQL, con.oleconnection)
Try
con.open()
cmd1.ExecuteNonQuery()
insertCommand.ExecuteNonQuery()
Catch
FailureText.Text = "Unable to add user"
Finally
con.close()
End Try
End If
Response.Redirect("Workers.aspx")
End Sub
the Insert into login part is working. the data is well inserted. but for the insert into worker part is not working. the data is not inserted into the table. the program shows no error and it still can work. what could possibly wrong with this?
Read another answer on OleDb I just answered on another post. You will be wide open to sql-injection too. Parmaeterize queries. By you concatenating strings to build one command, what if one value has a single-quote within the text entry. You are now hosed. What if someone puts malicious SQL commands and then deletes your records or entire table(s). Learn to parameterize your queries and also clean values, especially if coming from a web interface.
Your commands should probably be updated something like
Dim con As dbConn = New dbConn()
Dim SqlSelect As String
SqlSelect = "SELECT * FROM login Where user_id= #parmUserID"
Dim cmd As New OleDbCommand(SqlSelect, con.oleconnection)
cmd.Parameters.AddWithValue( "parmUserID", WorkerID_.Text )
Follow-suit with the Insert and update commands... parameterize them but using #variable place-holders in your commands.
Dim InsertSQL As String
InsertSQL = "INSERT INTO login (user_id, user_role, user_password, user_status) "
InsertSQL &= " VALUES ( #parmUser, #parmRole, #parmPwd, #parmStatus )"
Dim cmdInsert As New OleDbCommand(InsertSQL, con.oleconnection)
cmdInsert.Parameters.AddWithValue( "parmUser", WorkerID_.Text )
cmdInsert.Parameters.AddWithValue( "parmRole", "Worker" )
cmdInsert.Parameters.AddWithValue( "parmPwd", "12345" )
cmdInsert.Parameters.AddWithValue( "parmStatus", 1 )
Dim SqlUpdate As String
SqlUpdate = "INSERT INTO Worker (ID, WorkerID, WorkerName, DoB, Address, Phone, Email, CompanyName, PassportNum, PassportExp, VisaExp, VisaStatus, user_id) "
SqlUpdate &= " VALUES ( #parmID, #parmName, #parmDoB, etc... ) "
Dim cmdUpdate As New OleDbCommand(SqlUpdate, con.oleconnection)
cmdUpdate.Parameters.AddWithValue( "parmID", WorkerID_.Text )
cmdUpdate.Parameters.AddWithValue( "parmName", WorkerName.Text )
cmdUpdate.Parameters.AddWithValue( "parmDoB", DoB.Text )
-- etc with the rest of the parameters.
Final note. Make sure the data types you are trying to insert or update are of same type expected in the table. Such example is your "Birth Date" (DoB) field. If you are trying to insert as simple text, and it is not in an auto-converted format, the SQL-Insert might choke on it and fail. If you have a textbox bound to a DateTime type, then your parameter might be Dob.SelectedDate (such as a calendar control), or you could pre-convert from text to a datetime and then use THAT as your parameter value.
Other numeric values, leave as they are too, they should directly apply for the insert. You could also identify the AddWithValue() call the data type the parameter should represent (string, int, double, datetime, whatever)
You seem to have 12 parameters you wish to insert, and 13 arguments in the VALUES part of your insert query. is the Default seen in the values section below intentional?
INSERT INTO Worker (ID, ... VisaStatus) VALUES (default,"
ensure you have the correct number of parameters defined and added, then let us know, but i could be missing something else.

if record exists update else insert sql vb.net

I have the following problem, I am developing a Clinic application using vb.net, the doctor has the ability to add medical information using checkboxes checkbox2.text = "Allergy" textbox15.text is the notes for Allergy, I want to insert the record if the patient's FileNo(Textbox2.text) doesn't exist, if it does then update the notes only, so far I was able to update it after 3 button clicks I don't know why????
any help is appreciated :)
thanks in advance
Dim connection3 As New SqlClient.SqlConnection
Dim command3 As New SqlClient.SqlCommand
Dim adaptor3 As New SqlClient.SqlDataAdapter
Dim dataset3 As New DataSet
connection3.ConnectionString = ("Data Source=(LocalDB)\v11.0;AttachDbFilename=" + My.Settings.strTextbox + ";Integrated Security=True;Connect Timeout=30")
command3.CommandText = "SELECT ID,Type FROM Medical WHERE FileNo='" & TextBox2.Text & "';"
connection3.Open()
command3.Connection = connection3
adaptor3.SelectCommand = command3
adaptor3.Fill(dataset3, "0")
Dim count9 As Integer = dataset3.Tables(0).Rows.Count - 1
If count9 > 0 Then
For countz = 0 To count9
Dim A2 As String = dataset3.Tables("0").Rows(countz).Item("Type").ToString
Dim B2 As Integer = dataset3.Tables("0").Rows(countz).Item("ID")
TextBox3.Text = A2
If A2 = CheckBox1.Text Then
Dim sql4 As String = "update Medical set MNotes=N'" & TextBox22.Text & "' where FileNo='" & TextBox2.Text & "' and Type = '" & CheckBox1.Text & "' and ID='" & B2 & "';"
Dim cmd4 As New SqlCommand(sql4, connection3)
Try
cmd4.ExecuteNonQuery()
Catch ex As Exception
MsgBox(ex.Message)
End Try
ElseIf A2 = CheckBox2.Text Then
Dim sql4 As String = "update Medical set MNotes=N'" & TextBox15.Text & "' where FileNo='" & TextBox2.Text & "' and Type = '" & CheckBox2.Text & "' and ID='" & B2 & "';"
Dim cmd4 As New SqlCommand(sql4, connection3)
Try
cmd4.ExecuteNonQuery()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
Next
Else
If CheckBox1.Checked = True Then
Dim sql4 As String = "insert into Medical values('" & CheckBox1.Text & "',N'" & TextBox22.Text & "','" & TextBox2.Text & "')"
Dim cmd4 As New SqlCommand(sql4, connection3)
Try
cmd4.ExecuteNonQuery()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
If CheckBox2.Checked = True Then
Dim sql4 As String = "insert into Medical values('" & CheckBox2.Text & "',N'" & TextBox15.Text & "','" & TextBox2.Text & "')"
Dim cmd4 As New SqlCommand(sql4, connection3)
Try
cmd4.ExecuteNonQuery()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
End If
I think one of your problems may be related to your reducing the count of your table rows by 1 and then testing it above 0:
Dim count9 As Integer = dataset3.Tables(0).Rows.Count - 1
If count9 > 0 Then
Try changing to:
Dim count9 As Integer = dataset3.Tables(0).Rows.Count
If count9 > 0 Then
Also, make sure one of the check-boxes (CheckBox1 or CheckBox2) mentioned later in your code is ticked.
-- EDIT --
Sorry - didn't explain why! The reason is that the majority of array/list like structures in .NET are zero based (i.e. start counting from 0 instead of 1).
The best course of action for you is to maximize your productivity by allowing SQL to do what it does best. Assuming you are using SQL Server 2008, the MERGE function is an excellent use case for the conditions that you have supplied.
Here is a very basic example that is contrived based upon some of your code:
CREATE PROCEDURE [dbo].[csp_Medical_Merge]
#MType int, #FileNo varchar(20), #MNotes varchar(max), #ID int, #OtherParams
AS
BEGIN
MERGE INTO [DatabaseName].dbo.Medical AS DEST
USING
(
/*
Only deal with data that has changed. If nothing has changed,
then move on.
*/
SELECt #MType, #MNotes, #FileNo, #ID, #OtherParams
EXCEPT
Select [Type], MNotes, FileNo, ID, OtherFields from [DatabaseName].dbo.Medical
) As SRC ON SRC.ID = DEST.ID
WHEN MATCHED THEN
UPDATE SET
DEST.MNOTES = SRC.MNOTES,
DEST.FileNo = SRC.FileNo,
DEST.Type = SRC.Type
WHEN NOT MATCHED BY TARGET THEN
INSERT (FieldsList)
VALUEs (FileNo, MNotes, etc, etc);
END
GO

Data Reader formatting output

I'm using the following function to generate a list of users connected to a selected database. How would I change this to a single line for multiple identical results?
For example: "sa (3) - MYCOMPUTER" rather than listing "sa - MYCOMPUTER" three times?
Function ConnectedUsers(ByVal SelectedDatabase As String, ByVal SelectedInstance As String)
Dim myCommand As SqlCommand
Dim dr As SqlDataReader
Dim mystring As String = String.Empty
Try
Dim myConn As New SqlConnection(ConnectionString)
myConn.Open()
myCommand = New SqlCommand("select loginame,hostname from sysprocesses where db_name(dbid) = '" & SelectedDatabase & ";", myConn)
dr = myCommand.ExecuteReader()
While dr.Read()
mystring += GetFullName(dr(0).ToString().Trim()) & " - " & dr(1).Trim() & vbCrLf
End While
dr.Close()
myConn.Close()
Catch e As Exception
MessageBox.Show(e.Message)
End Try
Return mystring
End Function
Thanks.
The SQL Command should be
select loginame, count(*) as Nbr, hostname from sysprocesses where db_name(dbid) = '" & SelectedDatabase & "' group by loginame;"
and you should change the display to show the count (Nbr in this example) to be something like:
mystring += GetFullName(dr(0).ToString().Trim()) & "(" & dr(1).Trim() & ") - " & dr(2).Trim() & vbCrLf