BETWEEN clause in SQL - sql

I have a SQL statement to display data between two dates. I almost got it but there's a problem.
If I input March 1,2012 to March 7, 2012.. it should show data with dates between the two.. but it also show all of the dates under March 2012.. but whenever I input March 10, 2012 to March 30, 2012 the SQL works perfectly.. any help will be appreciated. thanks
SELECT
agentname, noofcalls, qualified, booking, resched,
actualbooking, sales, remarks,
concat(month,' ',day,',',year) as 'date'
FROM
tblagents
WHERE
(month between '" & cbosmonth.Text & "' AND '" & cboemonth.Text & "')
AND (day between '" & cbosday.Text & "' AND '" & cboeday.Text & "')
AND (year between '" & cbosyear.Text & "' AND '" & cboeyear.Text & "')"

you are doing string comparisons in each of your 'between'. Every number starting with a 1, a 2 or a 3, regardless of what follows it, i.e. 21, or 26, or 31, they are all lower than 7 if you look at them as strings. 1 to 30 works because you're only leaving 31 behind, and 30 < 31 as a String as well.
Do the concatenation first and then the between:
WHERE concat(month,' ',day,',',year)
BETWEEN concat(cbosmonth.Text,' ', cbosday.Text,' ',cbosyear.Text)
AND concat(cboemonth.Text,' ', cboeday.Text,' ',cboeyear.Text)
(check out for correct syntax, I'm just copy pasting from your question, not tried it)
BTW, unless you have a reason to, you probably should be storing the entire date in a single column with the right data time (datetime, timestamp, ...) and not three separated columns.

That is the incorrect way to store a date in database.
Change the date column to datatype date.
You could then do:
SELECT *
FROM table
WHERE bookingDate between to_date ('2012/03/01', 'yyyy/mm/dd')
AND to_date ('2012/03/07', 'yyyy/mm/dd');

This approach is wrong.
In order for a date to be between two interval dates it does not have to have a day number between the two dates, e.g. (pseudocode)
date = May-25-2012; startDate = March-15-2012, endDate = June-01-2012
date is clearly between startDate and endDate, yet
day(date) is 25, which is not between day(startDate) = 15 and day(endDate) = 1
more, as 15 is larger than 1, there are no numbers between them, so that condition will always be false
Similar example can be made for the month part of the date (e.g. date = May-25-2012; startDate = September-15-2010, endDate = Match-01-2015)
You need to take the values for day, month, year, and construct a Date either in the application or on the server and use that to compare the values against.
To make a date from text fields in VB
Dim startDate = new DateTime(
Convert.ToInt32(cbosyear.Text),
Convert.ToInt32(cbosmonth.Text),
Convert.ToInt32(cbosday.Text))
Note that this will fail if the user enters, e.g. "some text" for the year value. You'll need to add some data validations to achieve that.
To make a datetime from parts in SQL Server, take a look here, there are quite a few techniques explained.
Also, you should always avoid just pasting values into the sql string, that's asking for sql injection problems. You should do something like this:
Dim command = new SqlCommand()
command.CommandText = "SELECT .... FROM tblagents where DATEFROMPARTS(year, month, day) between #startDate AND #endDate"
command.Parameters.AddWithValue("#startDate", startDate)
command.Parameters.AddWithValue("#endDate", endDate)

Related

How to extract records from SQL table falling within certain date range? [duplicate]

I have a SQL statement to display data between two dates. I almost got it but there's a problem.
If I input March 1,2012 to March 7, 2012.. it should show data with dates between the two.. but it also show all of the dates under March 2012.. but whenever I input March 10, 2012 to March 30, 2012 the SQL works perfectly.. any help will be appreciated. thanks
SELECT
agentname, noofcalls, qualified, booking, resched,
actualbooking, sales, remarks,
concat(month,' ',day,',',year) as 'date'
FROM
tblagents
WHERE
(month between '" & cbosmonth.Text & "' AND '" & cboemonth.Text & "')
AND (day between '" & cbosday.Text & "' AND '" & cboeday.Text & "')
AND (year between '" & cbosyear.Text & "' AND '" & cboeyear.Text & "')"
you are doing string comparisons in each of your 'between'. Every number starting with a 1, a 2 or a 3, regardless of what follows it, i.e. 21, or 26, or 31, they are all lower than 7 if you look at them as strings. 1 to 30 works because you're only leaving 31 behind, and 30 < 31 as a String as well.
Do the concatenation first and then the between:
WHERE concat(month,' ',day,',',year)
BETWEEN concat(cbosmonth.Text,' ', cbosday.Text,' ',cbosyear.Text)
AND concat(cboemonth.Text,' ', cboeday.Text,' ',cboeyear.Text)
(check out for correct syntax, I'm just copy pasting from your question, not tried it)
BTW, unless you have a reason to, you probably should be storing the entire date in a single column with the right data time (datetime, timestamp, ...) and not three separated columns.
That is the incorrect way to store a date in database.
Change the date column to datatype date.
You could then do:
SELECT *
FROM table
WHERE bookingDate between to_date ('2012/03/01', 'yyyy/mm/dd')
AND to_date ('2012/03/07', 'yyyy/mm/dd');
This approach is wrong.
In order for a date to be between two interval dates it does not have to have a day number between the two dates, e.g. (pseudocode)
date = May-25-2012; startDate = March-15-2012, endDate = June-01-2012
date is clearly between startDate and endDate, yet
day(date) is 25, which is not between day(startDate) = 15 and day(endDate) = 1
more, as 15 is larger than 1, there are no numbers between them, so that condition will always be false
Similar example can be made for the month part of the date (e.g. date = May-25-2012; startDate = September-15-2010, endDate = Match-01-2015)
You need to take the values for day, month, year, and construct a Date either in the application or on the server and use that to compare the values against.
To make a date from text fields in VB
Dim startDate = new DateTime(
Convert.ToInt32(cbosyear.Text),
Convert.ToInt32(cbosmonth.Text),
Convert.ToInt32(cbosday.Text))
Note that this will fail if the user enters, e.g. "some text" for the year value. You'll need to add some data validations to achieve that.
To make a datetime from parts in SQL Server, take a look here, there are quite a few techniques explained.
Also, you should always avoid just pasting values into the sql string, that's asking for sql injection problems. You should do something like this:
Dim command = new SqlCommand()
command.CommandText = "SELECT .... FROM tblagents where DATEFROMPARTS(year, month, day) between #startDate AND #endDate"
command.Parameters.AddWithValue("#startDate", startDate)
command.Parameters.AddWithValue("#endDate", endDate)

SELECT * FROM MyTable WHERE [Date] = ([Date] + 8 hours)

My problem starts with the fact that my server is in a totally different country, so we have a difference of 8 hours (GMT).
So when I'm trying to do something like this:
CreateNewDataSet("SELECT * FROM tblArchives WHERE [Date] =" & DateAndTime.Today.Date.ToString("MM/dd/yyyy") & "'; & , "tblArchives")
It won't get all the results because it happened today in my country but yesterday where the server is based.
I tried unsuccessfully to use the DATEADD function.
Is there any way to do something like:
SELECT FROM WHERE [DATE+8 hours] =DateAndTime.Today.Date.ToString("MM/dd/yyyy")
Why don't you subtract the hours from the other side of the condition statement:
CreateNewDataSet("SELECT * FROM tblArchives WHERE [Date] =" & DateAdd(DateInterval.Hour, -8, DateAndTime.Today.Date).ToString("MM/dd/yyyy") & "'; & , "tblArchives")
You could move the date calculation in to the SQL so that you get the servers date something like
SELECT * FROM tblArchives WHERE Date = DateAdd(HH, +8,getdate())
try to run DateAdd(HH, +8,getdate()) to see the actual date and time it uses in your query. I have similar needs but I always set the time to be 1 millisecond after midnight to one millisecond before midnight. This will make sure you get all the data for a particular day.
you have to use DateTime.AddHours method
"SELECT * FROM tblArchives WHERE [Date] =" &
DateAndTime.Today.AddHours(-8).ToString("MM/dd/yyyy")
Instead of adding +8 hours to [Date] Column, add -8 to the current server date

Database contains European dateformat but query searches on American date format

Well, I'm using an MS Access database and I have a field Date. In the property of this field I have specified that the format should be 'dd/mm/yyyy'. However, when I use queries on the field, it searches with the date format 'mm/dd/yyyy'. I have no idea why it's doing this because I thought the queries adapt to the field properties and I haven't been able to find a solution online. My location and timezone are set in Europe. This is the query that I used:
SELECT Count(*) AS Amount
FROM Plays
WHERE PersonID = 1001 AND RestaurantID = 101358 and Date = #7/6/2016#
So, in this query it doesn't search the 7th of June 2016 but the 6th of July 2016. Both PersonID and RestaurantID are set as numbers; Date is set as Date/Time. How do I fix it so the query searches as the date format 'dd/mm/yyyy' as well without having to use any sql functions everytime?
If your query is written in VBA, you MUST write the dates using m/d/y. That's it.
I tend to construct my SQL statements using Format(expr, "\#mm\/dd\/yyyy\#"). E.g:
const kUsDtFmt = "\#mm\/dd\/yyyy\#"
sSql = "SELECT * FROM myTable WHERE dtUpdated = " & Format(Date(), kUsDtFmt )
Note: "\" is the escape key in format strings, meaning that the next character is taken as is.
If you simply wish to filter on today's date, do this:
SELECT Count(*) AS Amount
FROM Plays
WHERE PersonID = 1001 AND RestaurantID = 101358 and [Date] = Date()
For other dates, use DateSerial which frees you from format considerations:
SELECT Count(*) AS Amount
FROM Plays
WHERE PersonID = 1001 AND RestaurantID = 101358 and [Date] = DateSerial(2016, 6, 7)
If you concatenate string expressions, use the ISO sequence:
Dim SomeDate As Date
SomeDate = DateSerial(2016, 6, 7) ' or any other date value.
DateString = Format(SomeDate, "yyyy\/mm\/dd")
SQL = "SELECT Count(*) AS Amount " & _
"FROM Plays " & _
"WHERE PersonID = 1001 AND RestaurantID = 101358 and [Date] = #" & DateString & "#"
Note please, that Date is a reserved word, thus may have to be bracketed as shown.
Welp, I eventually found a solution to the problem:
"SELECT COUNT(*) as Amount FROM Plays WHERE PersonID = " & Me.txtPersonID &_
" AND RestaurantID = " & Me.txtRestaurantID & " AND Date = #" & Month(Me.txtDate)_
& "/" & Day(Me.txtDate) & "/" & Year(Me.txtDate) & "#"
I expected some of your solutions to work but for some reason(s) they didn't. Anyhow, now the correct date is searched and the correct value is returned. Thanks for the time you spent helping me.
Use FormatDateTime with vbShortdate to make sure your date is formatted the way the system expects it to be and not the way humans like to see it.

UK date format query?

I hope this is solvable.
Basically, I'm working with an SQL Server database table and in this table there is a field called matchdate. The format of the field is nchar(50).
There are over 2000 records in my table and the dates in the matchdate field are all in UK format, for example, "29/04/2014".
I am trying to query the table so I can pull out records between two UK dates. To do this I am using the following query:
SET DATEFORMAT DMY;
SELECT * from mytable
WHERE CAST(matchdate as datetime) BETWEEN '" & startdate & "' and '" & enddate & "'
order by cast([matchdate] as datetime) asc"
As you can probably tell this type of query is certainly not my strength. If the UK startdate value is "01/03/2014" and the UK enddate value is "23/04/2014" I get the following error:
Microsoft OLE DB Provider for SQL Server error '80040e07'
Conversion failed when converting date and/or time from character string.
I'm guessing this is because I am using two UK dates formats? How do I query the UK formatted "matchdate" field table using UK "start" and UK "end" formatted dates and get around this error?
PS: Unfortunately, I do not have access to the database table.
Try using the CONVERT function for the date so that you can specify the date standard
e.g. UK is 103
-- test
SELECT CONVERT(DATETIME, '10 January 2014', 103)
SELECT * from mytable WHERE CONVERT(DATETIME, matchdate, 103) BETWEEN '" & startdate & "' and '" & enddate & "' order by CONVERT(DATETIME, matchdate, 103) asc"

VB DataView.RowFilter and Cast Before Compare

In the following DataView.Rowfilter filter, Request_Date is a smalldatetime:
dv.RowFilter = "Request_Date >= '01/01/2012' and Request_Date <= '12/31/2012'"
The problem with this is that smalldatetime is MM/dd/yyyy hh:mm:ss, but it is compared to a string with the format 'MM/dd/yyyy'. This means that the filter will automatically convert the strings to smalldatetime, so the comparison only shows date/times between 1/1/2012 at 12AM and 12/31/2012 at 12AM. Any rows with dates later in the day on 12/31/2012 will not get picked up by this filter. I know that I can add a day to the end date or concatenate, say, 12:59:59 to the end of the date to pick up the other times in the day, but I was hoping for somthing more elegant, along the lines of the sql equivalent ...CONVERT(smalldatetime, Request_Date, 101) <= '12/31/2012'. Is there any way that I can get a different date format for a DataView field or am I stuck massaging the end date prior to comparison?
FYI, current best option is this:
dv.RowFilter = "Request_Date >= #" & dtpStartDate.DateText & "# and Request_Date <= #" & DateAdd(DateInterval.Day, 1, dtpEndDate.DateValue) & "#"
Thanks for your help!
If you're using at least .NET 3.5, you can use Linq-To-DataSet which is more readable:
DataTable filtered = dv.Table
.AsEnumerable()
.Where(r => r.Field<DateTime>("Request_Date") >= dtpStartDate.Value
&& r.Field<DateTime>("Request_Date") < dtpEndDate.Value.AddDays(1))
.CopyToDataTable();
Add using.System.Linq; and a reference to System.Data.DataSetExtensions.dll.
Edit: I've only just seen that VB.NET is tagged:
Dim filtered = From row In dv.Table
Where row.Field(Of DateTime)("Request_Date") >= dtpStartDate.Value AndAlso _
row.Field(Of DateTime)("Request_Date") < dtpEndDate.Value.AddDays(1)
Dim tblFiltered = filtered.CopyToDataTable()
Instead of using "<= 12/31/2012", just use "< 1/1/2013" - that is the most elegant and gets exactly what you want.