函数不一定是确定性的或不确定性的。根据其使用方式,有些功能可以确定:
以下函数并非总是确定性的,但是当以确定性方式指定它们时,可以在索引视图或计算列的索引中使用。
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
是不正确的,因此,我建议为其提交连接项。
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#所有,因为表和函数所有者必须相同)。