Updating SQL Server DateTime columns in VB.NET - sql

When updating records some DateTime values may look like 2015-06-25T01:35:52Z or 13 jun 2014
So when writing query I do:
Dim Query As String = "Update Activities set ActivityDate = '" & theDate & "' where customerid = 10"
(using vb.net)
but results in error. Is there a DateTime conversion I can use?

Using Data.SqlClient.SqlCommand.Parameters.Add:
MSDN: SqlCommand.Parameters Property
A parameterized query can handle this datetime conversion for you:
Protected Sub UpdateCustomerActivityDate(customerID As Integer, activityDate As DateTime)
Dim sql As String = "Update Activities set ActivityDate = #activityDate where customerid = #customerID"
Dim cmd As New Data.SqlClient.SqlCommand(sql)
cmd.CommandType = CommandType.Text
cmd.Parameters.Add("#customerID ", Data.SqlDbType.Int).Value = customerID
cmd.Parameters.Add("#activityDate ", Data.SqlDbType.DateTime).Value = activityDate
Try
Using connection As New SqlConnection(YourConnectionString)
connection.Open()
cmd.Connection = connection
cmd.ExecuteNonQuery()
End Using
Catch ex As Exception
Throw ex
End Try
End Sub

Related

Why SQL Server datetime datatype and datetimepicker search no result on VB.NET?

I am doing a function to search for records between 2 date on VB.NET. But I'm not sure is the conversion error or what the result is not showing. I store the date and time in database with DATETIME datatype, and I compare it with the datetimepicker of VB.NET. I guess it is because the datetime store in database include the date and the datatimepicker do not have time in it so the comparison to search the records will never be appear since the comparison is wrong because the datetimepicker do not have time in it.
Here's the code. The dateSelectFrom.value and dateSelectTo.value is the value of the datetimepicker
If rbFirstDate.Checked Then
Dim ds1 As String = Format(dateSelectFrom.Value, "YYYY-MM-DD")
cmd.CommandText = "SELECT OrderList.Id, OrderList.timeOrder,OrderDetail.foodID, Food.foodName,OrderDetail.qty, Food.price, OrderDetail.subtotal FROM OrderDetail INNER JOIN Food on OrderDetail.foodID = Food.Id INNER JOIN OrderList on OrderDetail.orderID = OrderList.Id WHERE (timeOrder = CONVERT(DATETIME, '" & ds1 & "', 102)) order by timeOrder"
End If
If rbBetweenDate.Checked Then
Dim ds1 As String = Format(dateSelectFrom.Value, "YYYY-MM-DD")
Dim ds2 As String = Format(dateSelectTo.Value, "YYYY-MM-DD")
cmd.CommandText = "SELECT OrderList.Id, OrderList.timeOrder,OrderDetail.foodID, Food.foodName,OrderDetail.qty, Food.price, OrderDetail.subtotal FROM OrderDetail INNER JOIN Food on OrderDetail.foodID = Food.Id INNER JOIN OrderList on OrderDetail.orderID = OrderList.Id WHERE (timeOrder BETWEEN CONVERT(DATETIME, '" & ds1 & "', 102) AND CONVERT(DATETIME, '" & ds2 & "', 102)) order by timeOrder"
End If
I had try to put the time format behind the date but it shows error conversion of datetime from string. Which the code looks like this :
Dim ds1 As String = Format(dateSelectFrom.Value, "YYYY-MM-DD HH:MI:SS")
Am I doing the conversion the wrong way or how do I assign the time to the datetimepicker.value?
I'm kinda confused by this datetimepicker and DATETIME datatype.
You should parameterize your query. Not only would this fix potential SQL injection vulnerabilities, but it will likely fix your underlying issue too.
Take a look at this example:
Dim commandString As String = "
SELECT
OrderList.Id,
OrderList.timeOrder,
OrderDetail.foodID,
Food.foodName,
OrderDetail.qty,
Food.price,
OrderDetail.subtotal
FROM
OrderDetail
INNER JOIN Food ON
OrderDetail.foodID = Food.Id
INNER JOIN OrderList ON
OrderDetail.orderID = OrderList.Id
WHERE
{{where}}
ORDER BY
OrderList.timeOrder;"
If (rbFirstDate.Checked) Then
commandString = commandString.replace("{{where}}", "OrderList.timeOrder = CONVERT(DATETIME, #0, 102)")
ElseIf rbBetweenDate.Checked Then
commandString = commandString.replace("{{where}}", "OrderList.timeOrder BETWEEN CONVERT(DATETIME, #0, 102) AND CONVERT(DATETIME, #1, 102)")
End If
Dim con As OleDbConnection
Try
con = New OleDbConnection("My Connection String Here")
Using cmd As OleDbCommand = New OleDbCommand(commandString, con)
' parameterize the query here
cmd.Parameters.Add("#0", OleDbType.Date).Value = dateSelectFrom.Value
If rbBetweenDate.Checked Then
cmd.Parameters.Add("#1", OleDbType.Date).Value = dateSelectTo.Value
End If
con.Open()
' do something with cmd here
con.Close()
End Using
Catch ex As Exception
Console.WriteLine(ex.Message)
Finally
If con IsNot Nothing Then
If con.State = ConnectionState.Open Then
' Close the connection if it was left open(exception thrown)
con.Close()
End If
con.Dispose()
End If
End Try
Obviously if you're using SQL Server then swap out the OLEDB namespace, but this is the basic gist.
The .Value property of a DateTimePicker returns a DataTime. Don't change it to a string and then have the database change it back to a date. The use of parameters should line up your .net DateTime with the Sql Server DateTime.
Private Function GetOrders() As DataTable
Dim dt As New DataTable
Dim sb As New StringBuilder
sb.Append("SELECT
OrderList.Id,
OrderList.timeOrder,
OrderDetail.foodID,
Food.foodName,
OrderDetail.qty,
Food.price,
OrderDetail.subtotal
FROM OrderDetail
INNER JOIN Food on OrderDetail.foodID = Food.Id
INNER JOIN OrderList on OrderDetail.orderID = OrderList.Id
WHERE 1 = 1")
Using cn As New SqlConnection("Your connection string"),
cmd As New SqlCommand()
cmd.Connection = cn
'this parameter will be used if either radio button is checked
cmd.Parameters.Add("#FirstDate", SqlDbType.DateTime).Value = dateSelectFrom.Value
If rbFirstDate.Checked Then
sb.AppendLine(" And timeOrder = #FirstDate")
ElseIf rbBetweenDate.Checked Then
sb.AppendLine(" And timeOrder BETWEEN #FirstDate AND #SecondDate")
cmd.Parameters.Add("#SecondDate", SqlDbType.DateTime).Value = dateSelectTo.Value
End If
sb.AppendLine(" Order By timeOrder;")
Debug.Print(sb.ToString) 'Just to check if everthing was added properly
cmd.CommandText = sb.ToString
cn.Open()
dt.Load(cmd.ExecuteReader)
End Using
Return dt
End Function

How do I read HasRow then Update?

Is it possible to read HasRow and then Update ?
This is the code what I have tried so far :
If conn.State = ConnectionState.Closed Then
conn.Open()
End If
Dim sqlcmd As New MySqlCommand("SELECT * FROM tbl_online_attendance where employees_id = '" & lvRealAtt.Items(itms).SubItems(0).Text & "' and in_time = '" & lvRealAtt.Items(itms).SubItems(1).Text & "' ", conn)
Dim dr As MySqlDataReader
dr = sqlcmd.ExecuteReader
If dr.HasRows Then
Dim query As String
query = "UPDATE tbl_online_attendance SET out_time = '" & lvRealAtt.Items(itms).SubItems(2).Text & "' where employees_id = '" & lvRealAtt.Items(itms).SubItems(0).Text & "' and in_time = '" & lvRealAtt.Items(itms).SubItems(1).Text & "' "
sqlcmd.Connection = conn
sqlcmd.CommandText = query
sqlcmd.ExecuteNonQuery() 'It error in this part
Else
End If
But it give's me error saying:
There is already an open DataReader associated with this Connection which must be closed first
Please avoid commenting Use Parameters Your code is Prone to SQL injection attack
You should not have to check connection state if you keep your connections local to the method that they are used. Database objects like connections and commands need to be closed and disposed as soon as possible. Using...End Using blocks take care of this for you even if there is an error. Don't open a connection until directly before the .Execute....
Don't pull down data when you only need Count. .ExecuteScalar returns the first column of the first row of the result set, which in this case, is the Count. If you have a large table you need to look into If Exists which will stop as soon it finds a match whereas Count looks at the whole table.
Always use Parameters. Never concatenate strings to build sql queries to avoid sql injection. I had to guess at the datatypes of the parameters. Check your database to get the actual types and adjust the code accordingly.
Private Sub OPCode(ByVal itms As Integer)
Dim RowCount As Integer
Using conn As New MySqlConnection("Your connection string"),
sqlcmd As New MySqlCommand("SELECT Count(*) FROM tbl_online_attendance where employees_id = #id and in_time = #inTime;", conn)
sqlcmd.Parameters.Add("#id", MySqlDbType.Int32).Value = CInt(lvRealAtt.Items(itms).SubItems(0).Text)
sqlcmd.Parameters.Add("#inTime", MySqlDbType.String).Value = lvRealAtt.Items(itms).SubItems(1).Text
conn.Open()
RowCount = CInt(sqlcmd.ExecuteScalar)
If RowCount > 0 Then
sqlcmd.CommandText = "UPDATE tbl_online_attendance SET out_time = #outTime where employees_id = #id and in_time = #inTime;"
sqlcmd.Parameters.Add("#outTime", MySqlDbType.String).Value = lvRealAtt.Items(itms).SubItems(2).Text
sqlcmd.ExecuteNonQuery()
End If
End Using
End Sub
Every SqlDataReader needs to be closed before you could execute another query.
so i suggest you to separate the sqlreader and the update query, put the reader into a boolean function to check either a row with those parameters exist or not.
Private Function HasRow(ByVal employeeid As Integer, ByVal date as DateTime) As Boolean
HasRow = False
Dim reader As SqlDataReader
'do select query here
'use the if reader.Read if you want to
HasRow = reader.HasRows
reader.Close()
End Function
Call the function before updating, if it's True then proceed the update. Let's say we put it into a Update Sub.
Private Sub Update()
If HasRows(parameters here) Then
'update query here
End If
End Sub

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.

getting error : Conversion failed when converting character string to smalldatetime data type. when querying again DB

I am getting an error when trying to insert into a table. As the error shows I know is because of the smalldatetime field. But I have tried several different things From other posts and its not working. Plus when I'm reading from the same table I use the same format for smalldatetime and it works. code show below. Any help would be really appreciated.
Code when trying to Insert a new row
.vb.net
Dim conn As String = "Your Connection String"
'Dim querystring As String = "INSERT INTO 'Where SupID='" & supervisor & "' Order By EmpNum"
Dim querystring As String = "INSERT INTO [AttendanceDB].[dbo].[tblAbsences]([fldEmployeeID] " & _
",[fldAbsentDate],[fldAbsentCode],[fldRuleViolationWarningType],[fldRuleViolationIssueDate] " & _
",[fldLOAEndDate]) VALUES('23','11-06-2014','NA','NULL','NULL','NULL')"
Using connection As New SqlConnection(conn)
Dim command As New SqlCommand(querystring, connection)
connection.Open()
Try
command.ExecuteNonQuery()
Catch ex As Exception
connection.Close()
End Try
End Using
I have also tried this code in SQL Management Studio
INSERT INTO [AttendanceDB].[dbo].[tblAbsences]([fldEmployeeID],
[fldAbsentDate],[fldAbsentCode],[fldRuleViolationWarningType],
[fldRuleViolationIssueDate],[fldLOAEndDate])
VALUES ('23','11-06-2014','NA','NULL','NULL','NULL')
This is the code that works when im reading from the same table when databinding to ViewGrid
Dim startdate As String = txtcalendarstart.Text
Dim enddate As String = txtcalendarstop.Text
startdate = startdate.Replace("/", "-")
enddate = enddate.Replace("/", "-")
Dim SqlDataSource2 As SqlDataSource = New SqlDataSource()
SqlDataSource2.ID = "SqlDataSource2"
Page.Controls.Add(SqlDataSource2)
SqlDataSource2.ConnectionString = "Data Source=SVR-SQLDB2;Initial Catalog=AttendanceDB;Integrated Security=True"
SqlDataSource2.SelectCommand = "SELECT * FROM [tblAbsences] WHERE [fldAbsentDate] BETWEEN '7-03-2014' AND '8-21-2014' ORDER BY [fldEmployeeID]"
GridView1.DataSource = SqlDataSource2
GridView1.DataBind()

Conversion of string to date type while passing from vb.net to sql server

I had the same issue while passing date variable from vb.net to SQL Server. I tried with Parameters as suggested above. Still I am facing the same issue. Pl guide.
Dim today As String
today = System.DateTime.Now.ToString("MM-dd-yyyy hh:mm:ss")
Dim todate As DateTime = DateTime.ParseExact(today, "MM-dd-yyyy hh:mm:ss", System.Globalization.DateTimeFormatInfo.InvariantInfo)
SQLCom.CommandType = CommandType.Text
SQLCom.Parameters.AddWithValue("#TODAY", CType(todate, Date))
SQLCom.CommandText = "SELECT DATEDIFF(MM,FORMAT(UPD_DATE,'dd-MM-yyyy'),FORMAT(#TODAY,'dd-MM-yyyy')) AS DATE_DIFF FROM tblEMP WHERE EMPID = '" & ID & "';"
Try
Dim daEmpExp As New SqlDataAdapter
daEmpExp.SelectCommand = SQLCom
SQLConn.Open()
daEmpExp.Fill(dsEmpExp)
SQLConn.Close()
Catch ex As Exception
MsgBox("Sorry!!! " & ex.Message)
Finally
If SQLConn.State = ConnectionState.Open Then
SQLConn.Close()
End If
End Try
End If
Return dsEmpExp
Still it catches error "Conversion failed when converting date and/or time from character string."
Why you need to convert date to string back and forth? Try to simply pass DateTime.Now as sql command parameter :
SQLCom.CommandType = CommandType.Text
SQLCom.Parameters.AddWithValue("#TODAY", System.DateTime.Now)
SQLCom.Parameters.AddWithValue("#ID", ID)
SQLCom.CommandText = "SELECT DATEDIFF(MM,FORMAT(UPD_DATE,'dd-MM-yyyy'),FORMAT(#TODAY,'dd-MM-yyyy')) AS DATE_DIFF FROM tblEMP WHERE EMPID = #ID;"
Try
......
End Try