问题
I have a database which has a column called stringNextDue that contains data like dates (UK format) and text (e.g "overdue", "completed")
I am trying to create a view that shows courses that are due within a month from now:
WHERE
CONVERT(DATETIME, mt.stringNextDue , 103) < DATEADD(MONTH, 1, GETDATE())
This throws an error:
Conversion failed when converting date and/or time from character string.
Which is probably due to the fact that stringNextDue may contain actual strings of text.
I tried using
WHERE
ISDATE(mt.NextDateString) = 1
AND CONVERT(DATETIME, mt.stringNextDue , 103) < DATEADD(MONTH, 1, GETDATE())
But ISDATE only accepts US date formats therefore ignoring a lot of actual dates as strings
Tried set dateformat 'dmy', which fixed the IsDate issue, but it cannot be used in views.
Any suggestions?
Server update is not an option
回答1:
If you cannot use the new TRY_CONVERT you might use a function like this:
Attention: This will not catch a wrong date like 31.06.2016, you'd have to modify the BETWEEN 1 AND 31 if you need this...
Attention2: If your text might include characters forbidden in xml you should replace < with <, > with > and & with & ...
CREATE FUNCTION dbo.TestDate(@TestString VARCHAR(100))
RETURNS DATE
AS
BEGIN
DECLARE @x XML=CAST('<x>' + REPLACE(@TestString,'.','</x><x>') + '</x>' AS XML)
DECLARE @p1 VARCHAR(10) = @x.value('x[1]','varchar(10)');
DECLARE @p2 VARCHAR(10) = @x.value('x[2]','varchar(10)');
DECLARE @p3 VARCHAR(10) = @x.value('x[3]','varchar(10)');
IF LEN(@p1)=2 AND ISNUMERIC(@p1)=1 AND CAST(@p1 AS INT) BETWEEN 1 AND 31
AND LEN(@p2)=2 AND ISNUMERIC(@p2)=1 AND CAST(@p2 AS INT) BETWEEN 1 AND 12
AND LEN(@p3)=4 AND ISNUMERIC(@p3)=1 AND CAST(@p3 AS INT) BETWEEN 1900 AND 2100
RETURN CONVERT(DATETIME, @TestString , 103);
RETURN NULL;
END
GO
SELECT
dbo.TestDate('overdue') AS SureNoDate
,dbo.TestDate('01.04.2016') AS EuropeanDate
,dbo.TestDate('2016.04.01') AS WrongFormat
,dbo.TestDate('01.13.2016') AS BadDate;
GO
DROP FUNCTION dbo.TestDate;
The result
SureNoDate EuropeanDate WrongFormat BadDate
NULL 2016-04-01 NULL NULL
You might pass back a valid date (RETURN GETDATE() ?) instead of RETURN NULL for your comparisson outside. This depends on your needs...
回答2:
It should be possible to replace WHERE clause using this:
SELECT *
FROM
-- sample data
(values('2015-01-01'),('01-01-2015'), ('x-x-x-x')) mt(NextDateString)
-- Replace WHERE statement with the following
CROSS APPLY
(
SELECT
RIGHT('0000'+PARSENAME(REPLACE(mt.NextDateString, '-', '.'), 1),4) yyy,
RIGHT('0000'+PARSENAME(REPLACE(mt.NextDateString, '-', '.'), 2),4) mmm,
RIGHT('0000'+PARSENAME(REPLACE(mt.NextDateString, '-', '.'), 3),4) ddd
) x
WHERE
x.yyy BETWEEN '1950' AND '2050'
AND x.mmm BETWEEN '0001' AND '0012'
AND x.ddd BETWEEN '0001' AND '0031'
AND ISDATE(mt.NextDateString) = 1
AND x.yyy+x.mmm+x.ddd < CONVERT(char(8), DATEADD(MONTH, 1, GETDATE()), 112)
Result:
NextDateString yyy mmm ddd
01-01-2015 2015 0001 0001
回答3:
Thank you for suggestions,
I fixed it by setting language to British on user settings
EXEC sp_defaultlanguage 'username', 'british'
来源:https://stackoverflow.com/questions/36310961/sql-convert-stringdate-or-text-to-date