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'은 (는) 결정적이지 않기 때문에 지속될 수 없습니다.

설명서에는

culture 인수가 제공되지 않으면 현재 세션의 언어가 사용됩니다.

그러나 문화 논쟁을 추가해도 변화가 없습니다

이것도 실패

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

Rextester 데모 : 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이 작동합니다. 은 Using SQL # (내가 쓴), 당신이 할 수있는 SQLCLR 라이브러리 ALTER TABLE SQL#.t ADD date_formatted_03 AS SQL#.Date_Format(date_col, 'd', 'en-US') PERSISTED;(테이블은 테이블 및 기능 소유자 필요하기 때문에 SQL 번호로 소유하는 것은 동일합니다).
Solomon Rutzky

답변:


5

함수가 반드시 결정적이거나 비 결정적이지는 않습니다. 사용 방법에 따라 결정적 일 수있는 몇 가지 기능이 있습니다 .

다음 함수는 항상 결정적인 것은 아니지만 계산 된 열이 결정적인 방식으로 지정된 경우 계산 된 열의 인덱스 된 뷰 또는 인덱스에서 사용할 수 있습니다.

CASTCONVERT같은 예이다. 지금까지 수행 한 테스트를 기반으로 FORMAT문자열 함수 임에도 불구하고 항상 결정적이지 않다고 말하는 것이 공정하다고 생각 합니다. 때로는 결정 론적 인 것인지 알고 싶다면 내가 생각할 수있는 유일한 기술은 만족할 때까지 다른 방법으로 호출하는 것입니다. 예를 들어, FORMAT숫자에 적용되는 것으로 간주합시다 . 숫자 입력 유형 은 10 가지뿐입니다 .

숫자 입력 유형

또한 9 가지 숫자 형식 만있는 것으로 보입니다 . 가능한 모든 조합에 대해 지속적인 열을 만들 수 있습니다. 이를 수행하는 일부 코드는 다음과 같습니다.

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/en-us/sql/t-sql/functions/format-transact-sql

format은 날짜 유형 또는 숫자 유형을 인수로 사용합니다. 날짜의 연도 부분을 잡는 것만으로도 년 함수를 사용할 수 없습니까?

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
Martin Smith

1
@MartinSmith, 재미있는. 개인적으로 나는 그것이 직감적으로 반박하고 "내장 문자열 함수는 모두 결정 론적"과 논리적으로 일치하지 않습니다.
Lennart

@Lennart 예제에 대한 대안을 주셔서 감사하지만 예제는 중요하지 않았습니다.
SqlZim

1
@ SqlZim, 나는 당신의 예가 단지 예일 것이라고 생각했지만 대신에 대안을 추가했습니다. 귀하의 질문이 정확히 무엇인지 잘 모르겠습니다. 형식이 문자열 함수인지 아닌지, 결정적인지 아닌지 또는 모든 것이 잘못 문서화되어 있는지 여부는 확실하지 않습니까?
Lennart
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.