Clone the value of a DATETIME column using arrays? - sql-server

I wrote the function below to get the values of two columns in a database, one is composed by integers (ID) and other dates/times in DATETIME format, in SQL Server 2008 R2. It stores the two values in two distinct arrays (lists), defined here:
Dim arrPartIDs As New List(Of Integer)
Dim arrPartUMDates As New List(Of Date)
My goal is to clone the datetime value of each row to the column 'Part_Previous_UMDate', which are currently set as NULL.
However, when my code execute the line:
WinToolSQLCmd.ExecuteReader()
After
WinToolSQLCmd = New SqlCommand("UPDATE WTData.dbo.Parts SET Part_Previous_UMDate = '" & arrPartUMDates.Item(intUMDateCounter) & "' WHERE ID = " & PartID.ToString, WinToolConnection)
The application returns an exception
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
I thought that by creating the array (list) arrPartUMDates as a list of date I could simply transfer its values back to the database, but apparently they are created as strings when added to the array...
What's the best approach to clone the DATETIME value in UMDate to Part_Previous_UMDate with full precision? I need to have full precision because later I´ll compare the values of the two columns in order to determine if they need an update.
Any ideas? I've searched for this error message but could not find anything related to dealing with dates in arrays...
Image of table here: http://i.stack.imgur.com/BYT1j.png
Code:
Function MirrorUMDateInPartsTable()
Dim arrPartIDs As New List(Of Integer)
Dim arrPartUMDates As New List(Of Date)
Dim WinToolConnection As New SqlConnection(StrGlobalWinToolConnection)
Dim intUMDateCounter As Integer = 0
WinToolSQLCmd = New SqlCommand("SELECT TOP 5 ID, UMDate FROM WTData.dbo.Parts WHERE WTData.dbo.Parts.Part_Previous_UMDate IS NULL ORDER BY ID", WinToolConnection)
WinToolConnection.Open()
Dim reader = WinToolSQLCmd.ExecuteReader()
While reader.Read()
arrPartIDs.Add(reader.Item(0))
arrPartUMDates.Add(reader.Item(1))
End While
reader.Close()
WinToolSQLCmd.Dispose()
If arrPartIDs.Count > 0 Then
For Each PartID As Integer In arrPartIDs
WinToolSQLCmd = New SqlCommand("UPDATE WTData.dbo.Parts SET Part_Previous_UMDate = '" & arrPartUMDates.Item(intUMDateCounter) & "' WHERE ID = " & PartID.ToString, WinToolConnection)
WinToolSQLCmd.ExecuteReader()
Next
End If
Return Nothing
End Function

You should use SqlParameter to add values to your query (and also to guard against SQL injection). Your problem is that you convert the date to a string in the code and SQL Server treats it as a string. The error about conversion from varchar occurs because the date format is not the one SQL Server uses. If you use parameters, it knows that you pass the date value and sends it correctly - you don't need to worry about any string conversions.
WinToolSQLCmd = New SqlCommand("UPDATE WTData.dbo.Parts SET Part_Previous_UMDate = #DateParam WHERE ID = #IdParam", WinToolConnection)
WinToolSQLCmd.Parameters.Add("#DateParam", arrPartUMDates.Item(intUMDateCounter))
WinToolSQLCmd.Parameters.Add("#IdParam", PartID)
Also, it's an update query, so you should use ExecuteNonQuery to execute your query:
WinToolSQLCmd.ExecuteNonQuery()
ExecuteReader is used when you want to read the data from the database.

Related

Display value from SQL Server on a VB.NET label

I want to get a value from a SQL Server column ID and show it on label.text with help the of following code:
Sub getID()
Dim selquery As String = ("select max(id)+1 from picture1")
Dim command As New SqlCommand(selquery, con)
con.Open()
Label1.Text = (command.ExecuteScalar)
con.Close()
End Sub
The scenario is to get maximum value from ID make it plus 1, and assign it to label.text, it works correctly when I have at least one record in my SQL Server table but if I have no record in my table picture1 then it shows error
You can leverage the ISNULL T-SQL function to deal with this:
SELECT ISNULL(MAX(id), 0) + 1 from picture1
If you have no records in your table, the max(id) part will return null, and you cannot +1 to a null.
To work around that problem use the COALESCE operator, like:
COALESCE(MAX(ID), 0) + 1
If there is a value returned from max(id) it will use that, otherwise it will return 0
The return value of command.ExecuteScalar is of type Object, so you have to check the value.
This should work:
Dim objResult As Object = command.ExecuteScalar
Dim intResult As Integer = If(TypeOf objResult Is Integer, DirectCast(objResult, Integer), 0)
Label1.Text = intResult.ToString
Also you should switch Option Strict On

SQL Server parameterized query with a WHERE clause with Nulls

VB.NET 2012, ADO.NET, SQL Server 2014
I setup a parameterized query that works well. I essentially read records from a DataTable that comes from a different source than my SQL Server. It's small enough that I elected to read record by record and build a query and hit the SQL Server for a match.
However I am having trouble getting a match when one of my fields is supposed to be matched for a null. I know a record exist because I can look at it in SQL Server directly and see it. With my parameterized query somehow the null is being translated improperly. I tried manually replacing the parameter #EngSerialNo with DBNull.Value and still doesn't work. Almost seems like I need two different queries depending if my DataTable value is null.
sqQry.AppendLine("SELECT CityCode,CarNum,RegNum,Event,EngSerialNum)")
sqQry.AppendLine("FROM [MyDB].[dbo].[Events]")
sqQry.AppendLine("WHERE (CityCode=#City AND CarNum=#CarNo AND RegNum=#RegNo AND Event=#Event AND EngSerialNum=#EngSerialNo)") 'this looks for a value in EngSerialNo
'sqQry.AppendLine("WHERE (CityCode=#City AND CarNum=#CarNo AND RegNum=#RegNo AND Event=#Event AND EngSerialNum IS NULL)") 'this looks for a Null in EngSerialNo
Dim cmd As New SqlCommand
With cmd
.Connection = connMyDb
.CommandType = CommandType.Text
.CommandText = sqQry.ToString
'cycle through each DataRow in the DataTable and check for returns
Dim total As Integer = 0
For Each row As DataRow In dtMain.Rows
.Parameters.Clear()
.Parameters.AddWithValue("#City", row.Item("City"))
.Parameters.AddWithValue("#CarNo", row.Item("CarNo"))
.Parameters.AddWithValue("#RegNo", row.Item("RegNo"))
.Parameters.AddWithValue("#Event", row.Item("Event"))
.Parameters.AddWithValue("#EngSerialNo", row.Item("EngSerialNo")) 'how do I get this to look for a null value when the DataTable contains a null value?
Dim rowsAffected As Integer = .ExecuteNonQuery()
total += rowsAffected
Next row
End With
Update: I ended up creating a dynamic SQL for every DataRow. Basically for each DataRow I check key fields for NULL or an actual value and create the appropriate SQL command text. I have 4 fields that could contain a NULL but for sake of simplicity I only demonstrated one here. I think the developer can follow the example to create their own query.
Dim cmd As New SqlCommand
With cmd
.Connection = connMyDb
.CommandType = CommandType.Text
'cycle through each DataRow in the DataTable and check for returns
Dim total As Integer = 0
For Each row As DataRow In dtMain.Rows
.CommandText = BuildSql(row)
.Parameters.Clear()
.Parameters.AddWithValue("#City", row.Item("City"))
.Parameters.AddWithValue("#CarNo", row.Item("CarNo"))
.Parameters.AddWithValue("#RegNo", row.Item("RegNo"))
.Parameters.AddWithValue("#Event", row.Item("Event"))
.Parameters.AddWithValue("#EngSerialNo", row.Item("EngSerialNo"))
Dim rowsAffected As Integer = .ExecuteNonQuery()
total += rowsAffected
Next row
End With
Private Function BuildSql(ByVal dr As DataRow) As String
Dim sqQry As New StringBuilder
sqQry.AppendLine("SELECT CityCode,CarNum,RegNum,Event,EngSerialNum)")
sqQry.AppendLine("FROM [MyDB].[dbo].[Events]")
If dr.Item("EngSerialNo") Is DBNull.Value Then
sqQry.AppendLine("WHERE (CityCode=#City AND CarNum=#CarNo AND RegNum=#RegNo AND Event=#Event AND EngSerialNum IS NULL)") 'this looks for a Null in EngSerialNo
Else
sqQry.AppendLine("WHERE (CityCode=#City AND CarNum=#CarNo AND RegNum=#RegNo AND Event=#Event AND EngSerialNum=#EngSerialNo)") 'this looks for a value in EngSerialNo
End If
Return sqQry.ToString
End Function
In SQL you can't compare null values, i.e. EngSerialNum = null always evaluates to false, even if the value in the field is null.
Either you can create the query dynamically so that you use is null to match the null values, or you can use an expression like this:
((EngSerialNum is null and #EngSerialNo is null) or EngSerialNum = #EngSerialNo)

Failed to convert parameter value from a String to a Int32 while passing integer variable

I have a stored procedure like this:
ALTER PROCEDURE [dbo].[T_TransactionSummary]
#startDate datetime,
#endDate datetime,
#locations integer
AS
BEGIN
.................
................
WHERE (Transaction_tbl.dtime BETWEEN #fromDate AND #toDate)
AND (Location_tbl.Locid IN (#locations))
I've got a ListBox which populates the #locations parameter (an integer), and two DateTimePicker controls for the #fromDate and #toDate.
I took my listbox value like this:
cnt = LSTlocations.SelectedItems.Count
Dim list As New List(Of Integer)
Dim locid As Integer
If cnt > 0 Then
For i = 0 To cnt - 1
Dim locationanme As String = LSTlocations.SelectedItems(i).ToString
locid = RecordID("Locid", "Location_tbl", "LocName", locationanme)
list.Add(locid)
Next
End If
Dim da As New SqlDataAdapter
Dim ds As New DataSet
Dim cmd23 As New SqlCommand("T_TransactionSummary", con.connect)
cmd23.CommandType = CommandType.StoredProcedure
cmd23.Parameters.Add("#startDate", SqlDbType.NVarChar, 50, ParameterDirection.Input).Value = startdate
cmd23.Parameters.Add("#endDate", SqlDbType.NVarChar, 50, ParameterDirection.Input).Value = enddate
cmd23.Parameters.Add("#locations", SqlDbType.Int).Value = String.Join(",", list)
da.SelectCommand = cmd23
da.Fill(ds)
if the code reach here i am getting error like this:
"Failed to convert parameter value from a String to a Int32
i know am getting error in this line
cmd23.Parameters.Add("#locations", SqlDbType.Int).Value = String.Join(",", list)
i want go the parameter to stored procedure like 1,2,3 only
i am using vb.net. what is wrong with my code..any help is great appreciate ..
If you define your stored procedure parameters are DATETIME (good thing!):
#startDate datetime,
then you must also define them as such in your VB.NET code!!
This is wrong:
cmd23.Parameters.Add("#startDate", SqlDbType.NVarChar, 50, ParameterDirection.Input).Value = startdate
It should be:
cmd23.Parameters.Add("#startDate", SqlDbType.DateTime).Value = ........
At this line:
cmd23.Parameters.Add("#locations", SqlDbType.Int).Value = String.Join(",", list)
You are producing a string like 1,2,3,4,5
Then you need to delete the delimitter when joining the list:
String.Join("", list)
That will produce a serie of numbers like 12345
SQL Server does not currently support the functionality as you describe (although I wish it did, I have this same problem.) If you have the ability to create objects on SQL server, you can create what is called a Table-Valued Parameters AKA parameters in the shape of a table.
Basically you create a "table type" on the server. It is an empty table that describes the shape of data table that you can pass to a parameter. In your case you would create a table with one column.
Let's walk through this example. Create your table type object on SQL server:
CREATE TYPE dbo.CategoryTableType AS TABLE
( CategoryID int, CategoryName nvarchar(50) )
Now in your stored procedures, or dynamic SQL in your code, you can declare table-valued parameters based on that type. This creates a stored procedure with one input parameter of type dbo.CategoryTableType. Now you can pass in a rows with columns CategoryID and CategoryName. Notice it must be read only.
CREATE PROCEDURE usp_UpdateCategories
(#tvpNewCategories dbo.CategoryTableType READONLY)
Now you can pass values to your parameterized SQL statement. Notice your SQL Parameter must be of type SqlDBType.Structured.:
Dim sqlParameter As New SqlClient.SqlParameter
sqlParameter.ParameterName = "#tvpNewCategories"
sqlParameter.SqlDbType = SqlDbType.Int
sqlParameter.Value = addedCategories
sqlParameter.TypeName = "dbo.CategoryTableType"
You create your input data as a VB or C# DataTable:
'Create a DataTable with the modified rows.
Dim addedCategories As DataTable = _
CategoriesDataTable.GetChanges(DataRowState.Added)
More info: http://msdn.microsoft.com/en-us/library/bb675163(v=vs.110).aspx
Side note: the simplest, but least elegant, way to do this is to have dynamic SQL in your code and do a string.replace and replace #tvpNewCategories with (1, 2, 3, 4)

How to insert date and retrieve records based on that entered date

I am a PHP-MySql Guy & new to the vb.net & SQL Server CE.
how to handle records based on dates ?
Consider any table(tbl_demo) with with some columns having 1 column to store today's date.
For example (table structure)- Id Name today
-- ----- -----
int nvarchar datetime
If i have following data in a table -
Id Name today
-- ----- -----
1 vikram 11/08/2013 11:16:57 PM
then how do i retrieve this record by providing only 11/08/2013 to the query ?
PS-
I have facing following problem while executing the query (here is the code snippet) -
Dim Ddate As Date
Ddate = MonthCalendar1.SelectionRange.Start.ToString
SQLquery = "SELECT id,today FROM tbl_demo WHERE today = '" & Ddate & "'"
ERROR :The data type is not valid for the boolean operation.[Data type (if known) = datetime,Data type (if known) = nvarchar]
Though it is not best to have functions in the fields in the where clause (performance wise) this will do the job.
"SELECT id,today FROM tbl_demo WHERE CONVERT(DATETIME,CONVERT(VARCHAR,today,120)) = CONVERT(DATETIME,CONVERT(VARCHAR,'" & Ddate.ToString() & "',120))"
An alternative would be providing the Date directly to ISO format:
"SELECT id,today FROM tbl_demo WHERE CONVERT(DATETIME,CONVERT(VARCHAR,today,120)) = CONVERT(DATETIME,CONVERT(VARCHAR,'" & Ddate.ToString("yyyyMMdd") & "',120))"
I am not sure if it is yyyyMMdd or yyMMdd for SQL CE, so better try both.
According to this MSDN article it should be "yyMMdd" but it could be a typo...
While experimenting...I got this working as follows (please correct me if i wrong)
Dim Ddate As Date
Dim d, m, y
Ddate = MonthCalendar1.SelectionRange.Start.ToString
d = Ddate.ToString("dd")
m = Ddate.ToString("MM")
y = Ddate.ToString("yyyy")
And the Query is :
SQLquery = "SELECT billId,c_id,amount FROM tbl_outward WHERE (DATEPART(dd, ddate) = '" & d & "' AND DATEPART(mm, ddate) = '" & m & "' AND DATEPART(yyyy, ddate) = '" & y & "')"
Here's a complete example using a Data Reader. This is appropriate if you are going to process one row at a time. If you need to hold all the rows in memory or perform further operations you may want to use ExecuteDataSet to get the values.
This example prints the row values to the command line.
Dim recordDate as DateTime = new DateTime(2013,8,11)
Using connection As SqlCeConnection = New SqlCeConnection("Data Source=Database.sdf;Persist Security Info=False;")
connection.Open()
Using command As SqlCeCommand = connection.CreateCommand()
command.CommandText = "Select id, name, today from demo where today = #date"
Dim dateParameter As SqlCeParameter
dateParameter = New SqlCeParameter("#date", DbType.DateTime)
dateParameter.Value = recordDate
command.Parameters.Add(dateParameter)
Using reader As SqlCeDataReader = command.ExecuteReader()
Do While reader.Read()
Dim id As Integer = reader.GetInt32(0)
Dim name As String = reader.GetString(1)
Dim today As DateTime = reader.GetDateTime(2)
Console.WriteLine("{0,-4} {1,-10} {2,-10}", id, name, today)
Loop
End Using
End Using
End Using
A few important things to note:
The Using statements automatically clear up unused resources when you are finished with them
The sql statement used is parameterised, which allows you to pass in a strongly typed value rather than a string.
The first argument to Console.WriteLine is a string format. {0, -4} is a placeholder that will be filled by the next argument. -4 say that the value should be displayed left aligned in a column 4 characters wide. For more information, see the String.Format method documentation on MSDN.

How to update by taking values from textboxes on windows form in vb.net

I want to take the values from textboxes on a windows form and then update the values in the sql server database...I want to update only those fields for which a value has been entered by the user and leave the fields for which the textboxes are left empty by the user.....How can I generate the query dynamically for such a situation???
Edit:
I haven't yet coded for the update option...Here is my insertion code and i wanted to implement the update feature the same way just couldn't figure out how i can generate the query dynamically....It's a Booking System application
Dim str As String ' defines str as a string variable
'takes insertion query as a string in str variable
str = "Insert into Bookings Values(#cust_id, #cust_name,#contact, #game, #courtno, #poolno, #tableno, #booking_date, #booking_time, #booking_duration)"
'defines a new command which takes query string and connection string as parameters
Dim cmd As New SqlCommand(str, con)
' defines Customer ID parameter and takes its value from the form
Dim prmCustID As New SqlParameter("#cust_id", SqlDbType.Char)
prmCustID.Value = MskdTxtCustId.Text
' defines Customer Name parameter and takes its value from the form
Dim prmCustName As New SqlParameter("#cust_name", SqlDbType.Char)
prmCustName.Value = TxtCustName.Text
' defines Contact parameter and takes its value from the form
Dim prmContact As New SqlParameter("#contact", SqlDbType.VarChar)
prmContact.Value = MskdTxtCntctno.Text
' defines Game parameter and takes its value from the form
Dim prmGame As New SqlParameter("#game", SqlDbType.Char)
prmGame.Value = TxtGame.Text
' defines Court No parameter and takes its value from the form
Dim prmCrtNo As New SqlParameter("#courtno", SqlDbType.Int)
If TxtCrtNo.Text = "" Then
prmCrtNo.Value = Convert.DBNull 'If the textbox is empty then places Null in databse field
Else
prmCrtNo.Value = CType(TxtCrtNo.Text, Integer) ' converts from string to integer
End If
' defines Pool No parameter and takes its value from the form
Dim prmPoolNo As New SqlParameter("#poolno", SqlDbType.Int)
If TxtPoolNo.Text = "" Then
prmPoolNo.Value = Convert.DBNull 'If the textbox is empty then places Null in databse field
Else
prmPoolNo.Value = CType(TxtPoolNo.Text, Integer) ' converts from string to integer
End If
' defines Table No parameter and takes its value from the form
Dim prmTblNo As New SqlParameter("#tableno", SqlDbType.Int)
If TxtTblNo.Text = "" Then
prmTblNo.Value = Convert.DBNull 'If the textbox is empty then places Null in databse field
Else
prmTblNo.Value = CType(TxtTblNo.Text, Integer) ' converts from string to integer
End If
' defines Booking Date parameter and takes its value from the form
Dim prmBookDate As New SqlParameter("#booking_date", SqlDbType.DateTime)
prmBookDate.Value = TxtBookDate.Text
' defines Booking Time parameter and takes its value from the form
Dim prmBookTime As New SqlParameter("#booking_time", SqlDbType.DateTime)
prmBookTime.Value = TxtBookTime.Text
' defines Booking Duration parameter and takes its value from the form
Dim prmBookDur As New SqlParameter("#booking_duration", SqlDbType.Int)
prmBookDur.Value = CType(TxtBookDur.Text, Integer)
'Command cmd takes all the parameters
cmd.Parameters.Add(prmCustID)
cmd.Parameters.Add(prmCustName)
cmd.Parameters.Add(prmContact)
cmd.Parameters.Add(prmGame)
cmd.Parameters.Add(prmCrtNo)
cmd.Parameters.Add(prmBookDate)
cmd.Parameters.Add(prmBookTime)
cmd.Parameters.Add(prmBookDur)
cmd.Parameters.Add(prmPoolNo)
cmd.Parameters.Add(prmTblNo)
Dim str1 As String ' defines string variable for taking select query
str1 = "select bookingID from Bookings" 'takes select query in string variable for retrieving booking ID from the databse
Dim cmd1 As New SqlCommand(str1, con) 'defines a new command which takes query string and connection string as parameters
Dim x As Integer ' defines an integer for storing booking ID
con.Open() 'sets the connection state to open
Using (con) 'specifies the connection which is to be used by the SQLcommands
cmd.ExecuteNonQuery() 'Executes the insertion query
Dim id As SqlDataReader = cmd1.ExecuteReader() 'Defines and initiates the datareader to read data from database using cmd1 command
While id.Read() 'Iterates the reader to read booking id
x = id("bookingID") 'stores the booking Id in variable x
End While
id.Close()
End Using
con.Close() 'sets the connection state to close
' shows message box with successful booking message
MessageBox.Show("New booking saved successfully" & vbCrLf & "Your Booking ID is " & x, "Saved Successfully", MessageBoxButtons.OKCancel, MessageBoxIcon.Information)
this is a very broad question and highly dependend on what type of data-access framework your are going to use.
You could go low-level and use SqlCommand (if you use MsSql) or OdbcCommand to wrap up all with a SQL Update statement, with setters only for the fields you changed.
You could do dataset/datatable/dataadapter, load the row change only the fields you changed and update the table again.
You could do the same with LingToSql or EF.
If you want details please tell us what you tried and what you want to use.

Resources