[英]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 个不同的值, 5
、 6
和7
,那么定义为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.