Using Dates in SQL Server 2012 Query - sql

I'm using SQL Server 2012 and I need to write a query that will extract data greater than a particular date. The date field is called 'CreatedOn" and dates are recorded in this format "2014-08-18 17:02:57.903".
Currently, the date part of my query stands as follows:
WHERE CreatedOn > '2014-08-18'
Problem is extracted data includes those of '2014-08-18'. It's like the > (greater than) is acting like >= (greater than or equal)!
How should I write my query if I need all data, say greater than '2014-08-18'?

Try the following condition. The problem is that 2014-08-18 is really 2014-08-18 00:00:00 (includes the hour), so any date time in that day will be greater.
WHERE CreatedOn >= '2014-08-19'

'2014-08-18' actually means '2014-08-18 00:00:00'
So if you do not want 18th you should put either '2014-08-19' or specify the hours you want your date to be bigger of.

As the others have said it is actually translating to CreatedOn > 2014-08-18 00:00:00
Instead try converting your datetime field to a short ate and compare those.
The 126 in Convert maps to the yyyy-mm-ddThh:mi:ss.mmm format.
WHERE CONVERT(char(10), CreatedOn,126) > '2014-08-18'

It sounds like when you're saying you want records "greater than '2014-08-18' you actually mean "records that occurred past 2014-08-18 23:59:59.999999" - you have to take into account time when working with dates, unless the time is otherwise removed (which in your sample data it was not.
You could do something like the following:
declare #gtDate datetime
set #gtDate = dateadd(d, 1, convert(datetime,convert(varchar(10), '2014-08-18', 101)))
....
WHERE CreatedOn >= #gtDate
Here we're taking your '2014-08-18', convert it to a varchar containing only the date (to help in case '2014-08-18' is ever '2014-08-18 12:00:00 as an example)
Then we convert the varchar back to a date, and add a day to it. In the end the statement says
Give me records that occured on 2014-08-19 or greater
EDIT:
Here's a fiddle demonstrating
http://sqlfiddle.com/#!6/90465/1
Note that we have 4 rows of data potential
insert into sampleData (Created)
select '2014-08-17'
union all select '2014-08-18'
union all select '2014-08-18 12:00:00'
union all select '2014-08-19'
union all select '2014-08-19 15:00:00'
only the bottom 2 rows (2014-08-19 and 2014-08-19 15:00:00) would be returned

Related

Date is string between hyphens in SQL Server

I have date formats that are as follows:
Date_str
19-12-2007
31-7-2009
3-1-2010
31-11-2009
etc.
I can't do the following:
CONCAT(RIGHT(Date_str,4),SUBSTRING(Date_str,3,3),LEFT(2))
because as you can see above, the dates are not the same length. Is there a way in SQL Server to extract the date as datetime/date?
I also tried
Convert(datetime, Date_str)
but it just threw an error:
The conversion of a varchar data type to a datetime data type resulted
in an out-of-range value.
If 2012+, I would use Try_Convert(). This will return bogus dates as NULL.
Example
Declare #YourTable Table ([Date_str] varchar(50))
Insert Into #YourTable Values
('19-12-2007')
,('31-7-2009')
,('3-1-2010')
,('31-11-2009')
Select *
,try_convert(date,Date_Str,105)
from #YourTable
Returns
Date_str (No column name)
19-12-2007 2007-12-19
31-7-2009 2009-07-31
3-1-2010 2010-01-03
31-11-2009 NULL -- Notice 11/31 is NOT a date
See https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql for date formats
You probably need
CONVERT(DateTime, Date_str, 105)
As I mentioned in the comments, the only realistic solution is to convert that string into a proper date-typed column. The current format doesn't allow date sorting, or search for a range of dates, eg to find entries in the last week, or between one date and the other.
Parsing with CONVERT or TRY_PARSE means that no indexes can be used to speed up queries. Each time :
WHERE CONVERT(Date, Date_str, 105) > '20170101'
is used, the server will have to scan the entire table to convert the data, then filter the rows.
If you can't change the type of the field itself, you can create a persisted computed column that returns the value as a date and add indexes to it. You'll be able to use that column for indexed querying:
alter table SomeTable add date2 as TRY_convert(Actual_Date,date_str,105) PERSISTED
create index IX_SomeTable_ActualDate on SomeTable (Actual_Date)
This will allow you to perform sorting without tricks:
SELECT *
FROM SomeTable
ORDER BY Actual_Date
Or run range queries that take advantage of the IX_SomeTable_ActualDate index:
SELECT *
FROM SomeTable
Where Actual_Date Between DATEADD(d,-7,GETDATE()) AND GETDATE()
If you have 1000 rows, you could get 1000 times better performance.
Existing applications won't even notice the change. Newer queries and applications will be able to take advantage of indexing and sorting
I had a similar problem: my column (<my_date_field>) had date values in the form of
2021-01
2021-02
2021-10
2021-12
and so on, with data type of nvarchar(4000), and I always ran into the Conversion failed when converting date and/or time from character string. error (when trying e.g. CAST(<my_date_field> AS DATE) or CAST(CAST(<my_date_field> AS VARCHAR(7)) AS DATE) etc.)
I was able to convert them to date with the following code:
SELECT
CONVERT(date, <my_date_field> + '-01') AS first_day_of_month
FROM my_table
which resulted in
2021-08-01
2021-07-01
2021-06-01
2021-05-01

Can't compare 2 dates in oracle correctly

I have this sql query which retrieve records until 12/7/2016 the problem is, oracle returns records which is from 12/6/2016 and below. May I ask is this the correct behavior?
SELECT DISTINCT ACCOUNT_NO
FROM TBL_CLIENT_FINANCIAL_ACTIVITY cfa
WHERE CAST(tran_date as DATE) <= TO_DATE('12/07/2016');
I am assuming you are using MM/DD/YYYY? Declare it in your to_date().
to_date('12/07/2016','MM/DD/YYYY')
Also, let's trunc that new date to match the date you have stated, otherwise those leftover hours minutes seconds are later than your to_date value.
trunc(CAST(tran_date as DATE)) <= to_date('12/07/2016','MM/DD/YYYY')

SQL Server : Comparing Time

I am trying to compare time in my SQL query. However, when I run the query, I get zero result but I can see that in the table, there are records that should appear.
The query is as such:
SELECT *
FROM dbo.Alarms
WHERE StartDate <= '26/08/2015'
AND StartTime <= CONVERT(varchar(5), GETDATE(), 108)
The StartDate is stored in the database as YYYY-MM-DD and it seems to work fine when I query only with the date.
However, when I add the StartTime is when things don't work. StartTime stores the value in the 24 hour clock format.
What am not doing right?
Thanks
Use a correct datetime format:
SELECT *
FROM dbo.Alarms
WHERE StartDate <= '2015-08-26' AND StartTime <= cast(GETDATE() as date)
Don't compare date/time values as strings. The data types are built into the language. Use them.
I have not explicitly used this scenario but comparing dates can be a problem depending on how the fields are compared.
eg: '28/07/2015' is not less than your startdate as 28 > 26.
You could try comparing dates reformatted into a YYYYMMDD format.
Cheers.

Convert DateTime SQL

I need to get only date and hours from datetime field. How do I do that?
My query:
select ImpFile, convert(nvarchar,ImpDate,21) as ImpDate
from nol_artikula_izmaina
The output from this query:
What I need is that it only shows me the date and the hour for example the field ImpDate should look like this: 2012-05-11 14:00:00:000 and 2012-05-11 16:00:00:000
Is that possible?
This works by getting the number of [whole] hours between "date 0" and ImpDate, then adding that to "date 0".
It's very similar in principle to removing the time (which gets the number of [whole] days) and can be used to "truncate" to any date part (though for seconds or smaller, you may need to use a different "floor" date than 0 to avoid an overflow).
SELECT ImpFile, DATEADD(hh, DATEDIFF(hh, 0, ImpDate), 0)
FROM nol_artikula_izmaina
Select using datepart.
http://msdn.microsoft.com/en-us/library/aa258265(v=sql.80).aspx

select statement using Between with datetime type does not retrieve all fields?

I'm facing a strange query result and I want to ask you why I'm facing this issue.
I store some datetime data into TestTable as following :
creation_time
-----------------------
2010-07-10 00:01:43.000
2010-07-11 00:01:43.000
2010-07-12 00:01:43.000
This table is created and filled as following :
create table TestTable(creation_time datetime);
Insert into TestTable values('2010-07-10 00:01:43.000');
Insert into TestTable values('2010-07-11 00:01:43.000');
Insert into TestTable values('2010-07-12 00:01:43.000');
when I execute this query , I get two rows only instead of three as I expected:
SELECT * FROM TestTable
WHERE creation_time BETWEEN CONVERT(VARCHAR(10),'2010-07-10',111) -- remove time part
and CONVERT(VARCHAR(10),'2010-07-12',111) -- remove time part
Or if I execute this query , the same issue ..
SELECT * FROM TestTable
WHERE CONVERT(datetime,creation_time,111) BETWEEN CONVERT(VARCHAR(10),'2010-07-10',111) -- remove time part
and CONVERT(VARCHAR(10),'2010-07-12',111) -- remove time part
My Question :
Why the last row ('2010-07-12 00:01:43.000') does not appear in
the result even if I set the date range to cover all the day from 2010-07-10 to 2010-07-12?
I use Sql server 2005 express edition with windows xp 32-bits.
I'm trying to don't use a workaround solution such as increasing the date range to cover additional day to get the days I want.
Thanks .
You need to remove the time part from creation_time as well. Just use the same CONVERT if it works.
Currently you're asking if 2010-07-12 00:01:43.000 is less than 2010-07-12 00:00:00.000, which is not true.
it does not show the date because you have removed the time part, which would make the date equivalent to '2010-07-12 00:00:00.000' and since the last row is greater than this, so it is not displaying in the query results.
Your script should look like this:
SELECT *
FROM TestTable
WHERE creation_time BETWEEN
convert(datetime, convert(char, '2010-07-10', 106))-- remove time part
and **DATEADD**(day, 1, convert(datetime, convert(char, '2010-07-**11**', 106))) -- remove time part and add 1 day
This script will return all between 2010-07-10 00:00:00 and 2010-07-12 00:00:00. Basically this means all items created in 2 days: 2010-07-10 and 2010-07-11.
Converting columns in your table for comparison can be costly and cause indexes to not be used. If you have a million rows in your table and you have an index on creation_time, you will be doing an index scan and converting all million values to a string for comparison.
I find it better to use >= the start date and < (end date + 1 day):
SELECT *
FROM TestTable
WHERE creation_time >= '2010-07-10'
AND creation_time < dateadd(day, 1, '2010-07-12')
And the reason your second one may not work is because format 111 uses slashes ("2010/07/10"), format 120 uses dashes ("2010-07-10"). Your converts aren't doing anything to your start and end date because you are converting a string to varchar, not a date. If you did this, it might work, but I would still recommend not doing the conversion:
SELECT * FROM TestTable
WHERE CONVERT(datetime, creation_time, 111) BETWEEN
CONVERT(VARCHAR(10), CONVERT(datetime, '2010-07-10'), 111) -- remove time part
and CONVERT(VARCHAR(10), CONVERT(datetime, '2010-07-12'), 111) -- remove time part
Date/time inclusive between 7/10/2010 and 7/12/2010:
SELECT * FROM TestTable
WHERE creation_time BETWEEN
CONVERT(VARCHAR,'2010-07-10',101) -- remove time part
and CONVERT(VARCHAR,'2010-07-13',101) -- remove time part