ISDATE函数用于TSQL中的不同日期格式

时间:2015-05-20 12:32:43

标签: sql-server sql-server-2008 tsql datetime format

我需要在视图的多个列中将DATETIME值转换为VARCHAR,以便在SQL Server 2008上的另一个应用程序中进行排序和格式化(以区域设置格式显示)。

目前有两个问题。

  1. ISDATE值的输入格式不同(但在 列级别)
  2. 也可能有错误的值(例如:20..05.2015)
  3. 不幸的是,TRY_CONVERT函数仅适用于SQL Server 2012及更高版本。

    ISDATE不起作用,因为视图包含不同的日期格式,我既不能在用户定义的函数内部也不能在视图中设置语言,这会导致FUNCTION TryConvertStringAsDatetime ( @value VARCHAR(MAX), @format INT ) 使用德语日期格式。

    我的问题有没有更简单的解决方案? 我的第一个想法是写一个像

    这样的函数
    SET @day =  character 1 and 2 
    SET @month = character 4 and 5
    SET @year = character 7, 8, 9 and 10
    SET @dateODBCFormat = @year - @month - @day (concatenated with hyphen and not subtracted :)
    IF ISDATE(@dateODBCFormat ) = 1
        RETURN CONVERT(DATETIME, @dateODBCFormat, 120)
    ELSE
        RETURN CONVERT(DATETIME, 0) (does the job)
    

    使用CONVERT函数的格式编号,但手动检查每种可能的格式让我有点害怕。

    示例:TryConvertStringAsDatetime('20 .05.2015',104)(带有一些伪代码)

    </option>

3 个答案:

答案 0 :(得分:3)

这是我现在提出的功能:

CREATE
FUNCTION TryConvertStringAsDatetime (   @value VARCHAR(MAX),
                                        @format INT
                                    )
RETURNS DATETIME
AS
/*
Tries to convert a given VARCHAR value to DATETIME.
Returns NULL if no value was specified or the value is not in the correct format.
*/
BEGIN

    DECLARE @length INT = LEN(@value)

    IF @length IS NULL OR @length < 10 OR @length > 23
        RETURN NULL

    DECLARE @day VARCHAR(2),
            @month VARCHAR(2),
            @year VARCHAR(4),
            @time VARCHAR(9)

    IF @format = 104 --dd.mm.yyyy hh:mi:ss(24h)
    BEGIN
        SET @day = SUBSTRING(@value, 1, 2)
        SET @month = SUBSTRING(@value, 4, 2)
        SET @year = SUBSTRING(@value, 7, 4) 
    END
    ELSE IF @format IN (120, 121) --yyyy-mm-dd hh:mi:ss(24h)
    BEGIN
        SET @year = SUBSTRING(@value, 1, 4)
        SET @month = SUBSTRING(@value, 6, 2)
        SET @day = SUBSTRING(@value, 9, 2)              
    END
    ELSE
        RETURN NULL -- currently only german and ODBC supported

    IF @length > 11
        SET @time = SUBSTRING(@value, 12, @length - 11)

    SET @value = @year + '-' + @month + '-' + @day + ISNULL(' ' + @time, '')

    IF ISDATE(@value) = 1
        RETURN CONVERT(DATETIME, @value, 121)

    RETURN NULL

END

答案 1 :(得分:1)

我可能会这样做:

{'b':'2'}

注意:测试长度并使用patindex仅确保一般格式,因此您需要在try块中调用此函数,以防日期和月份被反转并将导致转换错误。
另一方面,将支持的格式添加到此函数非常简单 - 您只需添加list子句,其中包含正确的CREATE FUNCTION TryConvertToDate ( @InputString varchar(20) ) RETURNS Datetime BEGIN DECLARE @DateTime datetime = NULL SET @DateTime = CASE WHEN LEN(@InputString) = 10 AND PATINDEX('[0-9][0-9].[0-9][0-9].[0-9][0-9][0-9][0-9]', @InputString)=1 THEN CONVERT(DateTime, @InputString, 104) -- German WHEN LEN(@InputString) = 10 AND PATINDEX('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]', @InputString)=1 THEN CONVERT(DateTime, @InputString, 120) -- ODBC ELSE NULL -- unsuported format END RETURN @DateTime END 和长度以及正确的转换样式。

另一个选项是确保字符串实际上可以转换为日期 这将使您的函数更复杂,因此更难编写,但更容易使用,因为它会减少产生转换错误的可能性:

when

答案 2 :(得分:0)

在SQLCLR中,你可能在速度和功能方面都有更好的运气(如@Tab和@Zohar在各种评论中所述)。

.NET / C#代码:

using System;
using System.Data.SqlTypes;
using System.Globalization;
using Microsoft.SqlServer.Server;

public class TryConvertStuff
{
    [SqlFunction(IsDeterministic = true, IsPrecise = true)]
    public static SqlDateTime TryConvertDateTime([SqlFacet(MaxSize = 50)] SqlString
        StringDate, [SqlFacet(MaxSize = 10)] SqlString Culture)
    {
        CultureInfo _Culture = CultureInfo.CurrentCulture;
        if (!Culture.IsNull && Culture.Value.Trim() != String.Empty)
        {
            _Culture = CultureInfo.GetCultureInfo(Culture.Value);
        }

        DateTime _RealDate;
        if (DateTime.TryParse(StringDate.Value, _Culture,
                               DateTimeStyles.None, out _RealDate))
        {
            return _RealDate;
        };

        return SqlDateTime.Null;
    }
}

<强>试验:

SELECT dbo.TryConvertDateTime(N'2019-04-20', N'en');  --  2019-04-20 00:00:00.000
SELECT dbo.TryConvertDateTime(N'2019-04-20f', N'en'); --  NULL
SELECT dbo.TryConvertDateTime(N'2019.04.20', N'en');  --  2019-04-20 00:00:00.000

SELECT dbo.TryConvertDateTime(N'20.04.2019', N'en');  --  NULL
SELECT dbo.TryConvertDateTime(N'20.04.2019', N'de');  --  2019-04-20 00:00:00.000
SELECT dbo.TryConvertDateTime(N'20.04.2019', NULL);   --  NULL