Convert varchar to Date, not work with AND in WHERE Clause - sql-server

I have a SQL Server table Companies which contains a column UserDefined4 of type nvarchar(100).
This column contains some text plus a date in the format DD.MM.YYYY
I want to select the records in the month of March and April 2014.
I am running this query,
SELECT
(Right(Companies.UserDefined4, 10))
FROM
Companies
WHERE
(Right(Companies.UserDefined4, 10) not like '%[^0-9.]%'
AND (Right(Companies.UserDefined4, 10) not like ''))
AND (CONVERT(Date,Right(Companies.UserDefined4, 10),104) >= '2014-03-01'
and
CONVERT(Date,Right(Companies.UserDefined4, 10),104) <= '2014-04-30')
This query throws an error
Error converting a string to a date and / or time.
I have checked one by one all the records and they contains date in proper format. The strange thing for me is that the same query runs if I put OR instead of AND in following part, in the same query:
(
CONVERT(Date,Right(Companies.UserDefined4, 10),104) >= '2014-03-01'
OR
CONVERT(Date,Right(Companies.UserDefined4, 10),104) <= '2014-04-30'
)
I know, its not a wise decision to save date as a NVarChar but I have to work with this data. I am not the one who designed this database.

I've had similar problems in the past and they were all due to some of the columns not ending with the expected characters (dates in your case) and the "guard clauses" (in your case the 1st two conditions in the WHERE) not stopping the query engine from applying the "range conditions" (in your case, the last two conditions in the WHERE).
Note that I don't know exactly why that happens (maybe query optimization, no "short-circuit" evaluation or the order in that the evaluation occurs isn't what we expect -- this is me speculating), but I've noticed that if you store an intermediate result of the query (with only the "guard clauses" applied) in a temporary structure (a table variable for example) and then apply the "range clauses" to that interim result, it'll work.
For example, this will work even if there are "bad" rows (rows that don't end in a date):
DECLARE #t TABLE (userdate CHAR(10))
INSERT #t
SELECT RIGHT(Companies.UserDefined4, 10)
FROM Companies
WHERE RIGHT(Companies.UserDefined4, 10) NOT LIKE '%[^0-9.]%'
AND RIGHT(Companies.UserDefined4, 10) <> ''
SELECT *
FROM #t
WHERE CONVERT(DATE, userdate, 104) >= '2014-03-01'
AND CONVERT(DATE, userdate, 104) <= '2014-04-30'
You can check a fiddle demonstrating the issue here.

Can you be sure that UserDefined4 really always contains a date in that format in the right-most 10 characters?
If so, you could create a computed column like this:
ALTER TABLE dbo.Companies
ADD DateFromUD4 AS CONVERT(DATE, RIGHT(UserDefined4, 10), 104) PERSISTED
and then the query becomes really simple:
SELECT
(list of columns)
FROM
dbo.Companies
WHERE
DateFromUD4 >= '20140301' AND
DateFromUD4 <= '20140430'
I like to use the ISO-8601 format (YYYYMMDD without any dashes) for specifying dates as string since this is guaranteed to work on any SQL Server regardless of the date and language settings.
Since the conversion goes to a DATE, you won't have to worry about time portions either - this is a date-only computed column. This works in SQL Server 2008 and newer.

Related

How does one find rows created today if the CreatedDate column is of type datetimeoffset?

I have a column named CreatedDate of type DateTimeOffset, and I need to query to see rows created today. If this column was of type DateTime I would do this:
SELECT *
FROM MyTable
WHERE CreatedDate >= GETDATE()
How does one accomplish this with a DateTimeOffset column, however?
Environment: SQL Server 2014
Take a look at the TODATETIMEOFFSET function that is built into SQL Server.
Here is an example of how it is used (-5 is my timezone offset...your usage may vary)...again, this also considers you are only worried about >= current time as your original question suggested. You would need to adjust usage of GETDATE() if you care about the entire day (see comment on original question).
select * from TestingDates d where d.CreatedDate >= TODATETIMEOFFSET(GETDATE(), '-05:00')

How to convert varchar into usable date in SQL Server?

I am having an issue converting an nvarchar into a date.
The column title is DOS and the dates are formatted like 05-03-2012.
I am trying to convert to a date so I can filter in the where clause.
I have seen explanations using CONVERT(datetime, DOS, 101) but I am not sure where this would go? In the select? In the where clause? Is this the best method to convert varchar into date?
SELECT BedSize
,avg(contributionmargin) AS ContributionMargin
FROM Summary
WHERE DOS > '06-30-2016'
GROUP BY bedsize
HAVING avg(contributionmargin) > 10000
ORDER BY contributionmargin DESC
In this example the where clause is just looking at the '06' in the date and selecting values that are greater than 06, so the results include:
07/01/2013
07/02/2009
08/31/2009
09/25/2012
11/03/2016
12/03/2008
The problem is that the years are ignored.
Option 1:
Add a new datetime column (let's suppose DOSDate) in the table and then run this query
update mytable set DOSDate = STR_TO_DATE(DOS,'%m-%d-%Y')
But future inserts in mytable will also needs to be converted and stored in DOSDate` column.
Option 2:
If you cannot add a new column, use this in where clause
select * from mytable where STR_TO_DATE(DOS,'%m-%d-%Y') > p_mydate
Since you have not provided a query, the above is a sample query to illustrate the point.
UPDATE
Initially you marked your question related to MySQL. For SQL Server you may use CAST or CONVERT instead of STR_To_DATE https://msdn.microsoft.com/en-us/library/ms187928(v=sql.90).aspx
I was able to use the convert function for SQL Server.
This code works:
SELECT BedSize
,avg(contributionmargin) AS ContributionMargin
FROM Summary
WHERE Convert(DATE, DOS, 101) > '06-30-2016'
GROUP BY bedsize
HAVING avg(contributionmargin) > 10000
ORDER BY contributionmargin DESC

SQL Server Converting int to Date

I have a scenario where I have an int column with the following dates for example:
20131210
20131209
What I want is, I want to convert the above to a date datatype so that I can use it with GETDATE() function.
This is my try but I am getting an error:
SELECT CONVERT(DATETIME, CONVERT(varchar(8), MyColumnName))
FROM MyTable
WHERE DATEADD(day, -2, CONVERT(DATETIME, CONVERT(CHAR(8), MyColumnName))) < GetDate()
This is the error I am getting:
Conversion failed when converting date and/or time from character string.
You have at least one bad date in your column (it could be 99999999 or 20130231 or who knows). This is what happens when you choose the wrong data type. You can identify the bad row(s) using:
SELECT MyColumnName FROM dbo.MyTable
WHERE ISDATE(CONVERT(CHAR(8), MyColumnMame)) = 0;
Then you can fix them or delete them.
Once you do that, you should fix the table. There is absolutely no upside to storing dates as integers, and a whole lot of downsides.
Once you have the date being stored in the correct format, your query is much simpler. And I highly recommend applying functions etc. to the right-hand side of the predicate as opposed to applying it to the column (this kills SQL Server's ability to make efficient use of any index on that column, which you should have if this is a common query pattern).
SELECT MyColumnName
FROM dbo.MyTable
WHERE MyColumnName < DATEADD(DAY, 2, GETDATE());
Try:
CREATE TABLE IntsToDates(
Ints INT
)
INSERT INTO IntsToDates
VALUES (20131210)
, (20131209)
SELECT CAST(CAST(Ints AS VARCHAR(12)) AS DATE)
FROM IntsToDates
I've had a similar problem where I need to convert INT to DATE and needed to cater for values of 0. This case statement did the trick for me
CASE MySourceColumn
WHEN ISDATE(CONVERT(CHAR(8),MySourceColumn)) THEN CAST('19000101' AS DATE)
ELSE CAST(CAST(MySourceColumn AS CHAR) AS DATE)
END
AS MyTargetColumn

how to match datetime column by passing date only in SQL Server

I have a Table, where there is a datetime Column, I want to match this column by passing only date & datetime column is heaving date & time both (i.e 25/06/2013 4:54:12 PM).
It's usually best in this situation to leave the column alone and do some manipulation on your parameter. So if you're passing a #SearchDate parameter, I'd do:
SELECT abc from mytable
where
datetimecolumn >= #SearchDate and
datetimecolumn < DATEADD(day,1,#SearchDate)
I believe that, if you're running on SQL Server 2008 or later, and use the following:
SELECT abc from mytable
where
CAST(datetimecolumn as date) = #SearchDate
That an index on datetimecolumn can be used. Whereas I'm certain that an index is usable given my first query. You should, in general, be wary of calling functions on columns - such actions can often cripple performance by forcing a full table scan.
And unlike you're accepted answer, I would always seek to avoid treating dates as strings - as soon as you do, you're inviting all kinds of issues around formatting.
datetime format in t-sql is a little tricky, first of all you need to be aware of date time (i.e 25/06/2013 4:54:12 PM) is greater than 25/06/2013 , so you need to use > and < operators, for ![enter image description here][1]example orderdate > '20130625' AND orderdate < '20130626' , sql server considers 'YYYYMMDD' as global datetime format and it is language independent. take a look at the attachement...
try -:
DECLARE #givenDate DATE;
DECLARE #t AS TABLE (
fld_DateTime DATETIME
)
SET #givenDate = '2013-04-24'
INSERT INTO #t ( fld_DateTime )
VALUES ('2013-04-23 14:37:59.580')
, ('2013-04-23 14:59:02.403')
, ('2013-04-23 15:15:36.890')
, ('2013-04-24 08:57:45.800')
, ('2013-04-24 10:44:56.663')
, ('2013-04-24 13:18:20.760')
, ('2013-04-25 09:38:55.503')
, ('2013-06-28 09:20:11.007')
, ('2013-06-28 12:37:04.973')
, ('2013-06-28 12:38:50.130')
, ('2013-07-03 15:27:36.167')
SELECT fld_DateTime
FROM #t
WHERE fld_DateTime >= #givenDate AND fld_DateTime < DATEADD(DAY, 1, #givenDate)
You can use CAST and CONVERT functions for converting date
http://msdn.microsoft.com/en-us/library/ms187928(v=sql.105).aspx
For example
select *
from datetimetable
where convert(char(10), datetimecolumn, 103) = '25/12/2013'
BUT remember, that this code is for testing purposes only.
I recommend you to play with different parameters of CONVERT function
in order to better understand it (and to play with different sizes of the first parameter)
please, view solutions in the other answers on your question to find out the best one for your environment

TSQL: Tune Dynamic Query Search

In reading on tuning TSQL queries, I've seen advice on avoiding (or being careful) about functions in the WHERE clause. However, in some cases - like searches that require dynamic dates from today's date - I'm curious if a query can be tuned further? For instance, the query below this uses the DATEADD function for the current date, which allows the user at anytime to get the correct information for the past thirty days:
SELECT *
FROM Zoo..Transportation
WHERE ArrivalDate BETWEEN DATEADD(DD,-30,GETDATE()) AND GETDATE()
If I try to eliminate the function, DATEADD, I could declare a variable that will pull that time and then query the data with that set value stored in the variable, such as:
DECLARE #begin DATE
SET #begin = DATEADD(DD,-30,GETDATE())
SELECT *
FROM Zoo..Transportation
WHERE ArrivalDate BETWEEN #begin AND GETDATE()
However, the Execution Plan and Statistics show the exact same number of reads, scans and batch costs.
In these instances of dynamic data (for instance, using today's date as a starting point), how do we reduce or eliminate the use of functions in the WHERE clause?
Functions in the where clause mean doing silly things like:
WHERE DATEPART(WEEK, ArrivalDate) = 1
Or
WHERE CONVERT(CHAR(10), ArrivalDate, 101) = '01/01/2012'
E.g. functions against columns in the where clause, which in most case destroy sargability (in other words, render an index seek useless and force an index or table scan).
There is one exception that I know of:
WHERE CONVERT(DATE, ArrivalDate) = CONVERT(DATE, GETDATE())
But I would not rely on this for any other scenario.
IME, using functions within a WHERE clause is only an issue when it operates on data from your query - this means that the function (which itself may be complex SQL) runs for each value in your query - this will likely cause a table scan or similar as the optmiser doesn't know which Index to use (if any).
Your example above is using DATEADD with the current date - the value is probably calculated once (or if it is calculated for each row in your result set, it won't affect the query plan as it doesn't contain data from your query).

Resources