TSQL Between 2 dates or >= and <=? - tsql

Morning experts. I have a very simple query that I can not seem to get working as it should.
I have a table that has invoiceNumber, CustNum, Datetime, and Grand_total
I want to pull all transactions between a set of dates in this example all transactions between 4/10/2014 and 4/23/2014. I was using:
SELECT Invoice_number
,CustNum
,DATETIME
,Grand_Total
FROM invoice_totals
WHERE custnum = '10014877'
AND DATETIME BETWEEN '2014-04-10'
AND '2014-04-23'
ORDER BY DATETIME DESC
I just realized if there are any dates on 4/23 that this does not show them.. I have tried to substuite using:
WHERE custnum = '10014877'
AND DATETIME >= '2014-04-10' AND DATETIME <='2014-04-23'
But it is still giving me the same results (ignoring any transactions that occured on 4/23)
the last record pulling up has a datetime stamp of 2014-04-22 12:26:08.000. There ARE 2 transactions on the 23'ed I am trying to include.
Thank you very much.

The part:
AND DATETIME <='2014-04-23'
is actually(according to TSQL):
AND DATETIME <='2014-04-23 00:00:000'
So you're quering from midnight and missing all the transactions from 00:01 to 23:59 on the 23rd.
Try:
AND DATETIME <='2014-04-23 23:59:999'
Or
AND DATETIME < '2014-04-24'
Both should include all the transactions for the day of the 23rd.

If you're working with continuous data, such as datetimes, it's usually better to switch to using a semi-open interval - an inclusive start date and an exclusive end date. Exclusive end dates are usually easier to calculate:
WHERE custnum = '10014877'
AND DATETIME >= '20140410' AND DATETIME <'20140424'
I've also switched to a safe, unambiguous date format.
The alternative, using <= or BETWEEN (which is just shorthand for a pair of >= and <= comparisons, so your two queries were identical) requires an inclusive end date. Which depending on the exact data type you're using may be 2014-04-23T23:59:59.997 or 2014-04-23T23:59:59.9999 or any number of other possibilities - if you get it wrong and overspecify the value, it'll get rounded to be 20140424 and then an inclusive comparison is incorrect.
And even if you get it right today, it's a pain to find all usage of this pattern if the data type of the column changes later.

BETWEEN is inclusive with respect to the boundaries.
However, I'm guessing that the type of your (poorly named) DATETIME field is .. DATETIME, so in the comparison, the date '2014-04-23' gets converted to a DATETIME as follows: '2014-04-23:00:000'. Thus, all records with DATETIME greater than that first moment on 04-23 are rejected.

Related

Compare some date predicate based on 1st of the month

I would like to get DATE format like in the title (yyyy-mm) from getdate() , in order to use it in where clause to get < and > dates from the one i formatted .So far i found almost everybody uses convert(varchar(10),getdate(),120) but that's varchar and it cant be check with < and > right ? So can someone help me to make a Date in format yyyy-mm or it's impossible ?
Why can't VARCHAR be compared using > and < operators? So long as you have a character string in an appropriate format, you can compare it just fine. For instance, CONVERT(VARCHAR(10), GETDATE(), 120) returns an ODBC Canonical format date, as "YYYY-MM-DD". This can obviously be compared using > and < to obtain correct results.
However, you would generally not want to do this in a database. Predicate such as this:
WHERE CONVERT(VARCHAR(10), [DateColumn], 120) >= '2018-02-26'
are considered "non-SARGable", and cannot use an index. This means that the server will apply brute force conversions to the underlying columns prior to the comparison, resulting in Index Scans or Table Scans, depending upon your schema.
For the vast majority of situations, you want the column to be used as an operand without any kind of conversion beforehand. Thus, the predicate should be expressed as:
WHERE [DateColumn] >= '2018-02-26'
This will result in an implicit cast of the '2018-02-26' operand into Date or DateTime (whatever the column type is), and this can use an index.
The absolute best would be an explicit cast such as this:
WHERE [DateColumn] >= CAST('2018-02-26' AS DATETIME)
This way, there is no room for mistakes, implicit conversions, or non-SARGable predicates.
Put simply, you do not want to do this in the way you are asking.
To look for records that match a specific year and month, simply use two where criteria in this manner:
declare #SomeDate date = '20180114'; -- This is any date.
-- This gets the first day of the month of the date above.
declare #MonthStart date = dateadd(month,datediff(month,0,#SomeDate),0);
-- This gets the first day of the following month of the date above.
declare #NextMonthStart date = dateadd(month,datediff(month,0,#SomeDate)+1,0);
select cols
from tables
where DateCol >= #MonthStart
and DateCol < #NextMonthStart;
if you have an existing datetime you should compare it against another time, using between for example. Why do you want to do a string comparison

Using Current Date Time in SAS

I am selecting the data from a table using a date string. I would like to select all rows that have a update time stamp greater than or equal to today.
The simplest way that I can think of is to put today's date in the string, and it works fine.
WHERE UPDATE_DTM >'29NOV2016:12:00'DT;
However, if I want to put something like today's date or system date, what should I put?
I used today(), but it returned all rows in the table. I am not sure if it's because today() in SAS refers to the date 1/1/1960? I also tried &sysdate, but it returned an error message seems like it requires a date conversion.
WHERE UPDATE_DTM > TODAY();
Any ideas? Your thoughts are greatly appreciated!
DATETIME() is the datetime equivalent of TODAY() (but includes the current time). You could also use dhms(TODAY(),0,0,0) if you want effectively midnight (or, for your example above, dhms(TODAY(),12,0,0) to get noon today).

CMIS Query : how to get result of one date only

I want to get data from one date only, example: 2014-06-16
in CMIS reference I know that we can use = (equal) operator that I think the time must be precised.
The alternative that i thought is to do like below :
First:
SELECT * FROM cmis:document WHERE cmis:creationDate >= TIMESTAMP '2014-06-16T00:00:00.000Z' AND cmis:creationDate< TIMESTAMP '2014-06-17T00:00:00.000Z'
Second:
SELECT P.tsi:DATENUM as date_traitement, L.tsi:type as type, P.tsi:statut as statut
FROM tsi:lot AS L JOIN tsi:pli AS P ON L.cmis:name = P.tsi:lot
WHERE
(P.tsi:DATENUM >= TIMESTAMP '2014-06-16T00:00:00.000Z' AND P.tsi:DATENUM < TIMESTAMP '2014-06-17T00:00:00.000Z')
The first one is running perfectly, I've got data from the 16 june BUT in the seconde I don't know WHY but I still got data from 2014-06-17
Note: tsi:DATENUM type is datetime
So could you say what's wrong OR how to get data from ONE date only?
The second one should work. The timestamps you are using are in GMT. If your timestamps are stored with a time zone offset it could be the reason why you are seeing times from 6/17 when you expect to only see times from 6/16.

Comparing two time columns in ASP.NET

I'm rather new to ASP.NET and SQL, so I'm having a tough time trying to figure out how to compare two time columns. I have a timestamped column and then a Now() column in an .mdb database. I need to have a gridview display records that are "Greater than or equal to 3 hours" from the timestamp. Any idea how I can accomplish this?
The Transact-SQL timestamp data type is a binary data type with no time-related values.
So to answer your question: Is there a way to get DateTime value from timestamp type column?
The answer is: No
You need another column of datetime2 type and use > operator to for comparison. You might want to set default value of getutcdate() to set it when each row is inserted.
UPDATE:
Since the column is of datetime type and not timestamp type (there is a type in SQL Server called timestamp, hence the confusion) you can just do
WHERE [TimeCalled] <= DATEADD(hour, -3, GETDATE())
Make sure your server is running in the same timezone as your code. It may be safer to store all dates in UTC. In that case use GETUTCDATE instead on GETDATE
Timestamps are generally used to track changes to records, and are updated every time the record is changed. If you want to store a specific value you should use a datetime field.
If you're using a DateTime Column and you want the result in TSQL try
DATEDIFF(Hour, 'Your DateTime Column here', 'pass Now() here' )
try to execute this example in TSQL:
select DATEDIFF(Hour, '2012-11-10 00:00:59.900', '2012-11-10 05:01:00.100')

T-SQL Between Dates Confusion

I am working with T-SQL in SQL Server 2000 and I have a table TRANSACTIONS which has a date column TRANDATE defined as DateTime, among many other columns which are irrelevant for this question..
The table is populated with transactions spanning many years. I ran into code, test, that has me confused. There is a simple SELECT, like this:
SELECT TRANDATE, RECEIPTNUMBER FROM TRANSACTIONS WHERE TRANDATE BETWEEN '12/01/2010' and '12/31/2010' ORDER BY TRANDATE
and its not returning two rows of data that I know are in that table.
With the statement above, the last row its returning, in order, has a TRANDATE of:
2010-12-31 00:00:00.000
When I modify the statement like below, I get the additional two rows for December 2010 that are in that table:
SELECT TRANDATE, RECEIPTNUMBER FROM TRANSACTIONS WHERE TRANDATE BETWEEN '12/01/2010 00:00:00' and '12/31/2010 23:59:59' ORDER BY TRANDATE
I have tried to find out why the BETWEEN operator doesnt include ALL rows for the 24 period in 12/31/2010 when using the first SELECT, above. And why does it need to have the explicit hours added to the SELECT statement as in the second, modified, statement to get it to pull the correct number of rows out?
Is it because of the way TRANDATE is defined as "DATETIME"?
Based on this finding, I think that am going to have to go through all of this old code because these BETWEEN operators are littered throughout this old system and it seems like its not pulling all of the data properly. I just wanted clarification from some folks first. Thanks!
A date is a point in time, not a time span.
'12/31/2010' is a point, too. Namely, it's the midnight of the 31st of December.
Everything that happened after this point is ignored.
That's exactly the behaviour you want (even if you haven't realised that yet).
Do not think that when you choose to omit the time part, it is magically assumed to be "any". It's going to be "all zeroes", that is, the midnight.
If you want to include the entire day in your query without having to specify 23:59:59 (which, by the way, excludes the last second of the day, between the moment 23:59:59 of the current day and the moment 00:00:00 of the next day), you can do that either by using strict inequalities (>, <) bounded by the first points of time you don't want:
WHERE TRANDATE >='12/01/2010 00:00:00' and TRANDATE < '01/01/2011'
or by comparing date values casted to DATE:
WHERE CAST(TRANDATE AS DATE) between '12/01/2010' and '12/31/2010'
(it is okay to put this type of cast in a WHERE clause, it is sargable).
As you have discovered, if you don't specify a time when entering a date, it defaults to midnight in the morning of the date. So 12/31/2010 stops at midnight when that day begins.
To get all dates for 12/31/2010, you can either specify the time, as you have done, or add one day to the ending date. Without a time, 1/1/2011 ends at the stroke of midnight on 12/31/2010. So, you could do BETWEEN 12/1/2010 AND 1/1/2011. You can use DATEADD to add the day in your SQL if that makes it easier.
There is some risk in that second approach of adding a day. You will get any records for 1/1/2011 that carry the time of 00:00:00.
Here's one way to perform the DATEADD:
DECLARE #FromDate datetime, #ToDate datetime
// These might be stored procedure input parameters
SET #FromDate = '12/1/2010'
SET #ToDate = '12/31/2010'
SET #ToDate = DATEADD(d, 1, #ToDate)
Then you use #ToDate in your WHERE clause in the BETWEEN phrase in the usual way.
'12/01/2010' means '12/01/2010 00:00:00' and '12/31/2010' means '12/31/2010 00:00:00'. This is why datetime values that fall later on the day on 12/31/2010 are excluded from your query results.
What would be your expected result if I would do this
Insert "12/31/2010" into your datetime column?
Exactly: 12-31-2010 00:00:00
So why would you expect it to be different as argument for a query?
You have kind of answered your own question already. What you have observed is the way SQL Server works.
If it is confirmation you need, this MSDN document has following to say about it
When the time part is unspecified, it
defaults to 12:00 A.M. Note that a row
that contains a time part that is
after 12:00 A.M. on 1998-0105 would
not be returned by this query because
it falls outside the range.
Edit
As for your comment, a datetime essentially is a floating point value.
Following script shows what numbers SQL Server works with.
40541.9749 (12/31/2010 23:23:59) can't be included when your upper bound is 40541 (12/31/2010)
DECLARE #ADateTime1 DATETIME
DECLARE #ADateTime2 DATETIME
DECLARE #ADateTime1AsFloat FLOAT
DECLARE #ADateTime2AsFloat FLOAT
SET #ADateTime1 = '12/31/2010'
SET #ADateTime2 = '12/31/2010 23:23:59'
SET #ADateTime1AsFloat = CAST(#ADateTime1 AS FLOAT)
SET #ADateTime2AsFloat = CAST(#ADateTime2 AS FLOAT)
SELECT #ADateTime1AsFloat, #ADateTime2AsFloat