format () เป็นฟังก์ชั่นสตริงในตัว nondeterministic …ใช่ไหม?


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;

ส่งคืนข้อผิดพลาดต่อไปนี้:

คอลัมน์ที่คำนวณ 'date_formatted_01' ในตาราง 't' ไม่สามารถคงอยู่ได้เนื่องจากคอลัมน์ไม่ได้ถูกกำหนดไว้

ในเอกสารระบุว่า

หากไม่ได้ระบุอาร์กิวเมนต์วัฒนธรรมจะใช้ภาษาของเซสชันปัจจุบัน

แต่การเพิ่มอาร์กิวเมนต์วัฒนธรรมจะไม่เปลี่ยนแปลงสิ่งต่าง ๆ

สิ่งนี้ก็ล้มเหลวเช่นกัน

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 ทำงาน การใช้ไลบรารีSQL # SQLCLR (ที่ฉันเขียน) คุณสามารถทำได้ALTER TABLE SQL#.t ADD date_formatted_03 AS SQL#.Date_Format(date_col, 'd', 'en-US') PERSISTED;(SQL เป็นเจ้าของตาราง # เนื่องจากเจ้าของตารางและฟังก์ชันต้องเหมือนกัน)
โซโลมอน Rutzky

คำตอบ:


5

ฟังก์ชั่นไม่จำเป็นต้องกำหนดหรือ nondeterministic มีฟังก์ชั่นบางอย่างที่สามารถกำหนดขึ้นอยู่กับการใช้งาน :

ฟังก์ชั่นต่อไปนี้ไม่ได้กำหนดไว้เสมอ แต่สามารถใช้ในมุมมองที่จัดทำดัชนีหรือดัชนีในคอลัมน์ที่คำนวณได้เมื่อมีการระบุในลักษณะที่กำหนด

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ไม่ถูกต้องดังนั้นฉันขอแนะนำให้ส่งรายการเชื่อมต่อ


6

FORMATเอกสารขณะนี้ได้รับการปรับปรุง (ในการตอบสนองของคุณรายการ Connect ) จะพูดว่า:

FORMATฟังก์ชัน nondeterministic

ในทำนองเดียวกันสตริงฟังก์ชั่น (Transact SQL)ในขณะนี้รวมถึง:

ฟังก์ชันสตริงในตัวทั้งหมดยกเว้นFORMATที่กำหนดไว้


1

ฉันไม่ใช่ผู้ใช้ธรรมดาของ sqlserver ดังนั้นฉันอาจเข้าใจผิด แต่ฉันเดาว่ารูปแบบนั้นไม่ใช่ฟังก์ชันสตริง ตามเอกสาร:

https://docs.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;

1
มันถูกระบุว่าเป็นฟังก์ชันสตริงในเอกสาร i.stack.imgur.com/aj0T2.png
Martin Smith

1
@MartinSmith น่าสนใจ โดยส่วนตัวแล้วฉันพบว่ามันขัดกับสัญชาตญาณและมันก็ไม่สอดคล้องกันอย่างมีเหตุผลกับ
Lennart

@ เลนนาร์ตฉันขอขอบคุณอีกทางเลือกหนึ่งสำหรับตัวอย่าง แต่ตัวอย่างไม่สำคัญ
SqlZim

1
@SqlZim ฉันคิดว่าตัวอย่างของคุณเป็นเพียงตัวอย่าง แต่ฉันได้เพิ่มทางเลือกในกรณี ฉันไม่แน่ใจว่าคำถามของคุณเป็นจริงหรือไม่ว่ารูปแบบเป็นฟังก์ชันสตริงหรือไม่ไม่ว่าจะกำหนดหรือไม่หรือว่าทั้งหมดนั้นมีเอกสารไม่ดีหรือไม่
Lennart
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.