Checking for date overlap across multiple date range objects - vb.net

I have several records in a database that have Start and End Dates
09/15/2011 - 09/30/2011
10/15/2011 - 10/22/2011
11/01/2011 - 11/15/2011
When user stores a record, I need to make sure dates don't overlap.
My simple code checks date ranges within a specific record (e.g. user enters 9/16/2011 or 10/21/2011, I throw an exception.)
But, on the slim chance a user gets creative (e.g. 10/14/2011 - 10/23/2011 or even 10/14/2011 to 11/16/2011), now they have circumvented my check.
BTW, the user could enter 10/14/2011 to 10/23/2011 if they were editing the record that contained values 10/15/2011 - 10/22/2011.
So, I'm trying to solve this riddle with a linq query. However, what I have isn't working exactly right.
UPDATE Nevermind about code not working. While trying to provide an example to expand on Miika's repsonse, I found my answer. So, giving credit to Miika for pointing me in the right direction and posting my working code below:
Here's my code:
Private Sub CheckForOverlap(myMonth As Messages.MyMonth)
Dim am As New MyMonth()
Dim amCollection As Messages.MyMonthCollection
Dim overlappingMyMonthDate As Boolean = False
Dim sErrorMsg As String = ""
'...non-applicable code omitted
Dim query = From s In amCollection _
Let s1 As MyMonth = CType(s, MyMonth) _
Where s1.AttendanceMonthID <> attendanceMonth.AttendanceMonthID And _
(CDate(attendanceMonth.StartDate) < CDate(s1.StartDate) And CDate(attendanceMonth.EndDate) > CDate(s1.EndDate)) _
Select s1
If query.Count > 0 Then
sErrorMsg = "Dates entered surround another entry"
End If
If overlappingMyMonthDate Then
Throw New Exception(sErrorMsg)
End If
End Sub
End Class
It all came down a LINQ query.

Do you need to do it in code or would SQL be an option? If the data is in a database, you could use the following query to check for overlaps.
SELECT COUNT(*)
FROM Table1
WHERE Table1.StartDate < 'endCheckDate'
AND Table1.EndDate > 'startCheckDate'
This will return a count of the number of overlaps found. 'endCheckDate' and 'startCheckDate' are your new query values (in date format). If your data is in a object collection in memory, then you could use LINQ. If you need help with a LINQ statement, let me know.

Related

Searching data by date - error

I'm using my VB.Net program to query a database in MS Access. In the database, I have a table that contain a "question_start" (Date/Time) field.
I would like to return the IDs of each record that occur on or after a date that I choose in my VB programme.
The data in the Access table, is being stored as Date/Time under a General Date format (e.g. '10/10/2016 15:48:01').
In VB.NEt, I am using the DateTimePicker object to select the date.
Below is the code I'm using to bring back all records that have a Start Date of 10/10/2016 (10th October 2016).
(Note 1: I have removed the time element from this particular search as I do not need my results to be time-sensitive here but are required later.)
Private Sub btnDateText_Click(sender As Object, e As EventArgs) Handles btnDateText.Click
Dim dt_QuestionDate As New DataTable()
dt_QuestionDate = getData("SELECT question_id
FROM tblQuestion
WHERE question_start => " & dtDateText.Value.ToString("dd-MM-yyyy") & ""
)
lstDateText.DataSource = dt_QuestionDate
lstDateText.DisplayMember = "question_id"
lstDateText.ValueMember = "question_id"
End Sub
**There are records in my database that should be returned, but I am receiving no values currently. I am not sure if it is how I've written the WHERE clause (I've done WHERE with "=>", ">=", and also "=") but I am not receiving records with the 10/10/2016.
Has anyone any ideas please? I don't know if it's because it's a simple mistake, or because of the time element that is stored in Access?
You need proper formatting of the string expression for the date value:
WHERE question_start => #" & dtDateText.Value.ToString("yyyy'/'MM'/'dd") & "#"

Best way to extract rows from DataTable (based on date field) and copy to another DataTable

I have a DataTable containing about 30 rows and I need to extract all rows having a date field bigger than a date stored into a variable.
(This code will be executed a lot of times)
I found three ways to do this but I would like to know how to choose because I don't know the differences between various codes.
Here is what I was able to write (and my worries):
1st way (DataTable.Select)
Dim SelectedRows() As DataRow = DT_DBData.Select("In_Date=#" & _
LastDate.ToString("yyyy-MM-dd") & "#")
Using New_Dt As DataTable = SelectedRows.CopyToDataTable
'Some code
End Using
I'm worried about the string format: I'm afraid that some rows may be not extracted because of a date formatting error.
2nd way (query Linq)
Using New_Dt As DataTable = (From DBData In DT_DBData.AsEnumerable() _
Where DBData.Field(Of Date)("In_Date") >= LastDate).CopyToDataTable
'Some code
End Using
I never used Linq and so I don't know what kind of issues can it give me.
3rd way (For Each Loop + If Then)
Using New_Dt As DataTable = DT_DBData.Clone
For Each dr As DataRow In DT_DBData.Rows
If dr("In_Date") >= LastDate Then
New_Dt.Rows.Add(dr.ItemArray)
End If
Next
'Some code
End Using
I'm not really worried about this code. I only think that the others could be better or faster (but I can't answer to this)
Faster is kind of irrelevant when dealing with 30 rows.
The first one is kind of wasteful. You start with a DataTable, Select to get a subset, then convert the result into a new DataTable. Time to extract matching Rows: 8 ms.
You can work with the SelectedRows array without putting it into a new DataTable. If it goes back to the DB after "some code", I would not extract it from the DT.
By the way, there is no reason to worry about matching date formats as long as the DB column is a date type (and therefore, the DataTable column will be also). Dates do not have a format; formats are just how computers (and by extension, us) display them to users.
Dim drs = dt.Select(String.Format("StartDate > '{0}'", dtTgt.Date), "")
The date type I pass will compare/filter just fine with the DateTime data for that column. Formats only come into play when you convert them to string, which is mostly only needed for those pesky users.
One option you missed might be especially useful if this will be done over and over: A DataView:
dt.Load(cmd.ExecuteReader)
' create dataview
Dim dv As New DataView(dt)
dv.RowFilter = String.Format("StartDate > '{0}'", dtTgt.Date)
dv.Sort = "StartDate asc"
' show/iterate/whatever
dgv.DataSource = dv
If the data goes back to the DB, using this method, the rows will retain all the rowstate values.

Checking for a null (or no result) from dataset

I'm working with the following bit of code in VisualBasic.NET. It's essentially supposed to be pulling a row ID from the table with specific conditions in mind. However, I would like to set up a failsafe of getting around those conditions if need be.
I'm trying to write an If statement to compare the Item(0) against but this bit of code seems to trigger no matter what. How can I compare to see if the Query being written as QuestionConnectionQuery is actually returning rows?
For i As Integer = 1 To intNoOfQuestions
'TODO: If there are no valid questions, pull up any of them that meets the difficulty requirement....
' Go into the Database and retrieve a question that hasn't been selected in the last seven days.
Dim QuestionConnectionQuery As New OleDb.OleDbCommand("SELECT TOP 1 Questions.QuestionID, Questions.QuestionCategory & ' : ' & Questions.QuestionSubCategory AS Category FROM Questions WHERE (((Questions.QuestionDifficulty)=[?])) OR (((Questions.LastDateRevealed) Is Null)) OR ((Questions.LastDateRevealed)>=DateAdd('d',-7,Now())) ORDER BY Rnd(QuestionID);", QuestionConnection)
QuestionConnectionQuery.Parameters.AddWithValue("?", intQuestionDifficulty(i - 1).ToString)
Dim QuestionDataAdapter As New OleDb.OleDbDataAdapter(QuestionConnectionQuery)
Dim QuestionDataSet As New DataSet
QuestionDataAdapter.Fill(QuestionDataSet, "Questions")
' If the result is not null... add it to the array.
If IsNothing(QuestionDataSet.Tables("Questions").Rows(0).Item(0)) Then
' Add that to the intQuestArray() array
intQuestArray(i - 1) = QuestionDataSet.Tables("Questions").Rows(0).Item(0)
Else
MessageBox.Show("ERROR: Not enough questions.")
QuestionDataAdapter.Fill(QuestionDataSet, "Questions")
End If
' Update the database by adding today's date to the "LastDateRevealed" column of the table.
Dim QuestionUpdateQuery As New OleDb.OleDbCommand("UPDATE Questions SET LastDateRevealed=NOW() WHERE QuestionID = [?]", QuestionConnection)
QuestionUpdateQuery.Parameters.AddWithValue("?", QuestionDataSet.Tables("Questions").Rows(0).Item(0).ToString)
QuestionUpdateQuery.ExecuteNonQuery()
Next
If IsDBNull(QuestionDataSet.Tables("Questions").Rows(0).Item(0)) Then
https://msdn.microsoft.com/en-us/library/tckcces5(v=vs.90).aspx

Conversion of Varchar to int

Need help! I cannot retrieve data in SQ L, because the value is 100-200
and it says that it needs to be converted it to Integer, but it is Var char data type.
So i think the problem is about the "-", then the error in the code is in
the data table code, so what to do?
Private Sub RetriveData(ByVal ID As String)
If Sql.HasConnection() = True Then
Dim DT As DataTable = Sql.ExecuteDataTable("SELECT (EmpID As varchar), FirstName,MidName,LastName,Gender,BirthDate,CivilStat,Address,ContactNum FROM EmployeeTable Where EmpID=" & ID)
For Each Data As DataRow In DT.Rows
EmpID_Txt.Text = Data(0)
FirstName_Txt.Text = Data(1)
MiddleName_Txt.Text = Data(2)
LastName_Txt.Text = Data(3)
Gender_CB.Text = Data(4)
BirthDate_DTP.Value = Data(5)
CivilStat_CB.Text = Data(6)
Address_Txt.Text = Data(7)
Contact_Txt.Text = Data(8)
Next
Else
MsgBox("System Database Cannot be Connected", MsgBoxStyle.Information)
End If
End Sub
Pass the ID as SQL Parameter to your query:
"SELECT (EmpID As varchar), FirstName,MidName,LastName,Gender,BirthDate,CivilStat,Address,ContactNum FROM EmployeeTable Where Empid=#empid"
Actually, assuming those 100-200 values are in a table somewhere, I would say the error was in the cranium of the developer who decided to use a varchar to store a numeric value :-)
Either that, or the developer who decided to take an otherwise free-form text field and assume it was always going to be a single numeric value.
As to how to fix it, one of those paragraphs simply needs to be worked around. If you want a single numeric value in the table, you should change it to a numeric type field, along the way going through all 100-200 style values and cleaning them up (into, for example, 150).
If you want to be able to store ranges, then your code that processes them is going to have to be more intelligent, such as extracting the lower and upper value from the column and running a loop to process all values within the range, or changing a query from (pseudo-codish query):
where EmpId = ?value?
into:
where EmpId >= ?low? and EmpId <= ?high?
We can't really tell you which is the best solution based on the information provided, this is likely to be a business decision rather than a technical one.
If my assumption is wrong and it's the ID argument (being used in the where clause) to the function RetriveData (sic), then you either need to stop users entering that, or make the code that processes the argument more intelligent (similar to the looping/changed-query suggestion above).

How to select only Date value No Time in LINQ to SQL?

I need to have a query which list all the user according to the date value in the database. Problems is this, in the database the date format is 5/5/2009 4:30:12 but I want to compare with 5/5/2009. I think the value of the based date is 5/5/2009 12:00:00 and that's why I couldn't query it.
The query is something like
dim db = new databcontext
dim user = from u in db.datacontext where u.signUpTime = 5/5/2009 select u.
May someone please check this problem.
Thanks in advance.
Your theory is correct. You should either use a range in your where clause:
u.SignupTime >= new DateTime(2009,5,5,0,0,0) AndAlso _
u.SignupTime < new DateTime(2009,5,6,0,0,0)
or check only the date:
u.SignupTime.Date = new DateTime(2009,5,5)