format()是一个不确定的内置字符串函数…对吗?


10

在发布有关缺少此内容的文档的连接项目之前,有人会确认我在这里不是简单地缺少什么吗?

在文档页面上format列出为字符串函数的位置:

“所有内置的字符串函数都是确定性的。” - 字符串函数(Transact-SQL)

format在相关页面上也没有提及不确定性:


但是,在尝试创建持久化的计算列时:

create table t (date_col date); 
insert into t values (getdate());
alter table t add date_formatted_01 as format(date_col,'YYYY') persisted;

返回以下错误:

表't'中的计算列'date_formatted_01'无法保留,因为该列是不确定的。

该文件指出

如果未提供文化参数,则使用当前会话的语言。

但是添加文化观点并不会改变一切

这也失败了

alter table t add date_formatted_02 as format(date_col, 'd', 'en-US' ) persisted

extrester演示:http://rextester.com/ZMS22966

dbfiddle.uk演示:http ://dbfiddle.uk/?rdbms=sqlserver_next&fiddle=7fc57d1916e901cb561b551af144aed6


1
这也会失败:alter table #t add date_formatted_01 as CONVERT(VARCHAR(20), FORMAT(date_col, 'YYYY', 'en-US')) persisted;。不确定为什么FORMAT不确定,尤其是在指定文化时。该date_formatted可以VARCHAR(20)(仍然存在),并使用经由触发器设置FORMAT。或SQLCLR起作用。使用SQL# SQLCLR库(我编写的),您可以做到ALTER TABLE SQL#.t ADD date_formatted_03 AS SQL#.Date_Format(date_col, 'd', 'en-US') PERSISTED;(表归SQL#所有,因为表和函数所有者必须相同)。
所罗门·鲁兹基

Answers:


5

函数不一定是确定性的或不确定性的。根据其使用方式,有些功能可以确定:

以下函数并非总是确定性的,但是当以确定性方式指定它们时,可以在索引视图或计算列的索引中使用。

CAST并且CONVERT是这样的例子。根据您到目前为止所做的测试,我认为可以公平地说FORMAT,尽管它是一个字符串函数,但并不总是确定性的。如果您想知道它有时是否具有确定性,我能想到的唯一技术就是尝试多种不同的调用方式,直到您满意为止。例如,让我们考虑FORMAT应用于数字。只有十种不同的数字输入类型

数字输入类型

似乎也只有九种不同的数字格式。可以尝试为所有可能的组合创建持久列。下面是执行此操作的一些代码:

DECLARE @FormatValue INT = 76767; -- change this if you want
DECLARE @FormatCulture VARCHAR(10) = 'en-US'; -- change this if you want
DECLARE @Format VARCHAR(1);
DECLARE @FormatType VARCHAR(10);
DECLARE @SQLForColumn VARCHAR(200);
DECLARE @TestNumber INT = 0;

BEGIN

    DROP TABLE IF EXISTS dbo.TargetTable;
    CREATE TABLE dbo.TargetTable (ID INT);

    DROP TABLE IF EXISTS #ColumnAddResults;
    CREATE TABLE #ColumnAddResults (
    FormatType VARCHAR(10),
    [Format] VARCHAR(1), 
    Succeeded VARCHAR(1), 
    ErrorMessage VARCHAR(1000)
    );

    drop table if exists #Types;
    create table #Types (FormatType VARCHAR(10));

    INSERT INTO #Types VALUES
    ('bigint'), ('int'), ('smallint'), ('tinyint'), ('decimal')
    , ('numeric'), ('float'), ('real'), ('smallmoney'), ('money');

    drop table if exists #Formats;
    create table #Formats ([Format] VARCHAR(1));

    INSERT INTO #Formats VALUES 
    ('C'), ('D'), ('E'), ('F'), ('G'), ('N'), ('P'), ('R'), ('X');

    DECLARE format_statements CURSOR LOCAL FAST_FORWARD FOR 
    SELECT #Types.FormatType, #Formats.[Format]
    FROM #Formats
    CROSS JOIN #Types;

    OPEN format_statements;

    FETCH NEXT FROM format_statements   
    INTO @FormatType, @Format;  

    WHILE @@FETCH_STATUS = 0  
    BEGIN
        SET @TestNumber = @TestNumber + 1;
        SET @SQLForColumn = 'alter table dbo.TargetTable add NewColumn' + CAST(@TestNumber AS VARCHAR(10))
        + ' as FORMAT(CAST(' +  CAST(@FormatValue AS VARCHAR(10)) + ' AS ' + @FormatType + '), '
        + '''' + @Format + ''', ''' + @FormatCulture + ''') persisted';

        BEGIN TRY
            EXEC (@SQLForColumn);
            INSERT INTO #ColumnAddResults VALUES (@FormatType, @Format, 'Y', NULL);
        END TRY
        BEGIN CATCH
            INSERT INTO #ColumnAddResults VALUES (@FormatType, @Format, 'N', ERROR_MESSAGE());
        END CATCH;

        PRINT @SQLForColumn;

        FETCH NEXT FROM format_statements   
        INTO @FormatType, @Format;  
    END;

    CLOSE format_statements;  
    DEALLOCATE format_statements;  

    SELECT * FROM dbo.TargetTable;
    SELECT * FROM #ColumnAddResults;
    DROP TABLE #ColumnAddResults;

END;

这是输出示例:

测试代码输出

对于一些输入值和区域性,我无法将任何列添加到表中。我没有详尽尝试所有可能的区域性,因为在SQL Server中找不到它们的列表。

至少可以肯定地说,关于确定性的文档FORMAT是不正确的,因此,我建议为其提交连接项。



1

我不是sqlserver的普通用户,所以我可能会误会,但是我的猜测是格式不是字符串函数。根据文档:

https://docs.microsoft.com/zh-cn/sql/t-sql/functions/format-transact-sql

格式采用日期类型或数字类型作为参数。如果您只想获取日期的年份部分,就可以使用年份功能吗?

alter table t 
    add date_formatted_01 as year(date_col) persisted;

如果要使用字符串表示形式:

alter table t 
    add date_formatted_01 as cast(year(date_col) as char(4)) persisted;

1
它在文档中列为字符串函数。 i.stack.imgur.com/aj0T2.png
马丁·史密斯

1
@MartinSmith,有趣。我个人认为它与直觉相反,并且在逻辑上也与“所有内置字符串函数都是确定性的”不一致。
Lennart

@Lennart我感谢该示例的替代方法,但该示例并不重要。
SqlZim

1
@SqlZim,我认为您的示例只是一个示例,但为防万一,我添加了一个替代方法。我不确定您的问题到底是什么,格式是否是字符串函数,是否是确定性的,还是所有这些都没有被正确记录?
Lennart
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.