在我发布关于这方面缺乏文档的连接项目之前,会有人确认我不是简单地遗漏了一些东西吗?
在docs页面上,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' ) persistedrextester演示:http://rextester.com/ZMS22966
dbfiddle.uk演示:http://dbfiddle.uk/?rdbms=sqlserver_next&fiddle=7fc57d1916e901cb561b551af144aed6
发布于 2017-05-27 18:21:01
函数不一定是确定性的或非确定性的。有一些函数可以是确定性的取决于它们的使用方式:
以下函数并不总是确定性的,但如果以确定性方式指定,则可以在计算列上的索引视图或索引中使用。
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;以下是输出的示例:

对于一些输入值和区域性,我无法将任何列添加到表中。我没有穷尽地尝试所有可能的区域性,因为我在Server中找不到它们的列表。
至少可以得出这样的结论:关于FORMAT的确定性的文档是不正确的,所以我建议为它提交一个连接项。
发布于 2017-08-17 03:14:19
FORMAT文档现在已经是已更新 (作为对您的连接项的响应)来表示:
FORMAT函数是不确定的。
同样,字符串函数(Transact-SQL)现在包括:
除
FORMAT外,所有内置字符串函数都是确定性的。
发布于 2017-05-27 14:06:40
我不是sqlserver的常规用户,所以我可能弄错了,但我的猜测是,这种格式不是字符串函数。根据文件:
https://learn.microsoft.com/en-us/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;https://dba.stackexchange.com/questions/174739
复制相似问题