简体   繁体   English

将可变精度传递给 TIMEFROMPARTS function

[英]Passing variable precision to TIMEFROMPARTS function

I'm trying to build a function that takes a string as input representing a time variable with no separators.我正在尝试构建一个 function,它将一个字符串作为输入,表示一个没有分隔符的时间变量。 The fraction part could have variable precision.分数部分可以具有可变精度。

This is the code I came up with:这是我想出的代码:

CREATE FUNCTION [dbo].[Convert_FullStringToTime]
(
    -- Add the parameters for the function here
    @inputString VARCHAR(17),
    @fractionsPrecision INT = 0
)
RETURNS TIME(7)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @Result TIME(7)

    -- Add the T-SQL statements to compute the return value here
    SELECT @Result = 
        TIMEFROMPARTS(
            LEFT(@inputString, 2),                      --hh
            SUBSTRING(@inputString, 3, 2),              --mm
            SUBSTRING(@inputString, 5, 2),              --ss
            RIGHT(@inputString, @fractionsPrecision),   --ff
            @fractionsPrecision
        )

    -- Return the result of the function
    RETURN @Result
END

But I'm getting an error:但我收到一个错误:

Scale argument is not valid.比例参数无效。 Valid expressions for data type time scale argument are integer constants and integer constant expressions.数据类型时标参数的有效表达式是 integer 个常量和 integer 个常量表达式。

Do I have to understand I really have to write a constant for the precision parameter???我必须明白我真的必须为精度参数写一个常量吗???
Why on earth has this been done that way?为什么要这样做呢?

Is there a better solution than using a case statement to overcome this ridiculous problem?有没有比使用 case 语句更好的解决方案来克服这个荒谬的问题?

This the combination of function I came up with, taking into account the precision inherent to the TIME datatype.这是我想出的 function 的组合,考虑到TIME数据类型固有的精度。 (Thanks to @Larnu ) (感谢@Larnu

First, the padding function (which SQL SERVER also lacks...)首先,填充 function(SQL SERVER 也缺少...)

CREATE FUNCTION [dbo].[Rpad] 
(
    -- Add the parameters for the function here
    @inputString VARCHAR(MAX),
    @paddingCharacter VARCHAR(1),
    @paddingLength INT
)
RETURNS VARCHAR(MAX)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @Result VARCHAR(MAX)

    -- Add the T-SQL statements to compute the return value here
    SELECT @Result = 
        LEFT(@inputString + REPLICATE(@paddingCharacter, @paddingLength), @paddingLength)

    -- Return the result of the function
    RETURN @Result

END
GO

Then the Time conversion function, which will always return a 7 precision TIME data type.然后将时间转换为 function,这将始终返回一个 7 精度的 TIME 数据类型。

CREATE FUNCTION [dbo].[Convert_FullStringToTime]
(
    -- Add the parameters for the function here
    @inputString VARCHAR(13)
)
RETURNS TIME(7)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @Result TIME(7)

    -- Add the T-SQL statements to compute the return value here
    SELECT @Result = 
        TIMEFROMPARTS(
                LEFT(@inputString, 2),                        --hh
                SUBSTRING(@inputString, 3, 2),                --mm
                SUBSTRING(@inputString, 5, 2),                --ss
                RIGHT([dbo].RPAD(@inputString, '0', 7), 7),   --ff
                7
            )


    -- Return the result of the function
    RETURN @Result
END

The error is actually telling you that what you want to do is explicitly not allowed.该错误实际上是在告诉您明确不允许您要执行的操作。 The precision parameter for TIMEFORPARTS must be a literal; TIMEFORPARTS的精度参数必须是文字; it cannot be an expression, a column value or a variable.它不能是表达式、列值或变量。 For your FUNCTION there is, in truth, little/no point in having a "variable" precision value either;实际上,对于您的FUNCTION来说,具有“可变”精度值也没有什么意义; a FUNCTION must also have an explicit data type defined and that include the length/scale/precision. FUNCTION必须定义一个明确的数据类型,包括长度/比例/精度。 You initially had your FUNCTION defined as a time , which is a synonym for time(7) , and you have now change the FUNCTION to demonstrate that.您最初将FUNCTION定义为time ,它是time(7)的同义词,现在您更改了FUNCTION以证明这一点。 As such it wouldn't matter what value the precision was passed, your FUNCTION would always return a time(7) .因此,传递的精度值无关紧要,您的FUNCTION始终返回time(7)

To address your latter comments:要解决您后来的评论:

Why on earth has this been done that way?为什么要这样做呢?

Is there a better solution than using a case statement to overcome this ridiculous problem?有没有比使用 case 语句更好的解决方案来克服这个荒谬的问题?

I'm going to address your second comment first;我将首先解决您的第二条评论; it isn't a "ridiculous problem", the real problem is you want a value that doesn't have a strict definition.这不是一个“荒谬的问题”,真正的问题是你想要一个没有严格定义的值。 T-SQL is a declarative and compiled langauge; T-SQL 是一种声明式和编译式语言; you need to explicity define what data types a value is.您需要明确定义值是什么数据类型。 The fact you want a variable precision value is a strong indication of an XY Problem , however, what that problem is I don't know.您想要可变精度值这一事实是XY Problem的强烈指示,但是,我不知道那个问题是什么。 There likely is a "better solution" to what you actually want to do, but without knowing what that is, we can't access that question here.对于您实际想要做的事情,可能有一个“更好的解决方案”,但不知道那是什么,我们无法在此处访问该问题。

As for why it's done that way, I come back to the point of that the language is declarative and compiled;至于为什么这样做,我回到了语言是声明式和编译式的观点; as such if you could pass a variable/expression then SQL Sevrer would know what data type to compile a column as.因此,如果您可以传递变量/表达式,那么 SQL Sevrer 将知道将列编译为哪种数据类型。 Take the following very simple statement:采取以下非常简单的陈述:

SELECT TIMEFROMPARTS(0,0,0,0,V.I) AS T
FROM (VALUES(5),(6),(7))V(I)

Here the column VI being (trying to be) used to define the precision for TIMEFROMPARTS .这里的VI列(试图)用于定义TIMEFROMPARTS的精度。 The problem though is that VI has 3 different values, 5 , 6 , and 7 , so what is the data type for the column defined as T ?但问题是VI有 3 个不同的值, 567 ,那么定义为T的列的数据类型是什么? Should it be 7 ?应该是7吗? 5 ? 5 SQL Server doesn't know, because at the time it compiles the statement it cannot make an informed decision; SQL 服务器不知道,因为在编译语句时它无法做出明智的决定; for a table (rather than a VALUES table construct) the compiler wouldn't read the table first to then make a decision, that would be awful for performance.对于表(而不是VALUES表构造),编译器不会先读取表然后做出决定,这对性能来说会很糟糕

As such you must use a literal to tell SQL Server what precision you need.因此,您必须使用文字来告诉 SQL 服务器您需要什么精度。 Just like when you define a variable, you can't use the syntax varchar(@Len) or when you CONVERT a column you can't use the syntax CONVERT(decimal(TP,TS),MyColumn) .就像定义变量时,不能使用语法varchar(@Len) ,或者在CONVERT列时不能使用语法CONVERT(decimal(TP,TS),MyColumn)

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

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