简体   繁体   English

SQL将字符串(日期或文本)转换为日期

[英]SQL convert string(date or text) to date

I have a database which has a column called stringNextDue that contains data like dates (UK format) and text (eg "overdue", "completed") 我有一个数据库,其中有一个名为stringNextDue的列,其中包含日期(英国格式)和文本(例如“逾期”,“已完成”)等数据

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. 这可能是由于stringNextDue可能包含实际的文本字符串。

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 ISDATE只接受美国日期格式,因此忽略了很多实际日期作为字符串

Tried set dateformat 'dmy' , which fixed the IsDate issue, but it cannot be used in views. 尝试set dateformat 'dmy' ,修复了IsDate问题,但不能在视图中使用。

Any suggestions? 有什么建议?

Server update is not an option 服务器更新不是一个选项

If you cannot use the new TRY_CONVERT you might use a function like this: 如果你不能使用新的TRY_CONVERT你可以使用这样的函数:

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... 注意:这不会像31.06.2016那样错误的日期,如果你需要,你必须修改BETWEEN 1 AND 31 ...

Attention2: If your text might include characters forbidden in xml you should replace < with &lt; 注意2:如果您的文本可能包含xml中禁止的字符,则应替换< with &lt; , > with &gt; > with &gt; and & with &amp; &&amp; ... ...

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. 你可以传回一个有效的日期( RETURN GETDATE() ?)而不是RETURN NULL为你的comparisson外。 This depends on your needs... 这取决于你的需求......

It should be possible to replace WHERE clause using this: 应该可以使用以下替换WHERE子句:

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

Thank you for suggestions, 谢谢你的建议,

I fixed it by setting language to British on user settings 我通过在用户设置上将语言设置为英语来修复它

EXEC sp_defaultlanguage 'username', 'british'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM