định dạng () là một hàm chuỗi tích hợp không đặc trưng, ​​đúng không?


10

Trước khi tôi đăng một mục kết nối liên quan đến việc thiếu tài liệu về điều này, liệu ai đó sẽ xác nhận rằng tôi không chỉ đơn giản là thiếu một cái gì đó ở đây?

Trên trang tài liệu formatđược liệt kê dưới dạng hàm chuỗi:

"Tất cả các hàm chuỗi dựng sẵn là xác định." - Hàm chuỗi (Transact-SQL)

Cũng không có đề cập đến formatviệc không đặc biệt trên các trang liên quan:


Tuy nhiên, khi cố gắng tạo một cột được tính toán bền vững:

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

Trả về lỗi sau:

Cột được tính 'date_formatted_01' trong bảng 't' không thể tồn tại vì cột không xác định.

Các tài liệu nói rằng

Nếu đối số văn hóa không được cung cấp, ngôn ngữ của phiên hiện tại sẽ được sử dụng.

nhưng thêm một đối số văn hóa không thay đổi mọi thứ

Điều này cũng thất bại

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

bản demo của rextester: http://rextester.com/ZMS22966

bản demo dbfiddle.uk: http://dbfiddle.uk/?rdbms=sqlserver_next&fiddle=7fc57d1916e901cb561b551af144aed6


1
Điều này cũng thất bại : alter table #t add date_formatted_01 as CONVERT(VARCHAR(20), FORMAT(date_col, 'YYYY', 'en-US')) persisted;. Không chắc chắn tại sao FORMATkhông mang tính quyết định, đặc biệt là khi chỉ định văn hóa. Các date_formattedcột có thể được VARCHAR(20)(vẫn kiên trì) và thiết lập thông qua kích hoạt sử dụng FORMAT. Hoặc SQLCLR hoạt động. Sử dụng thư viện SQL # SQLCLR (mà tôi đã viết), bạn có thể làm được ALTER TABLE SQL#.t ADD date_formatted_03 AS SQL#.Date_Format(date_col, 'd', 'en-US') PERSISTED;(bảng được sở hữu bởi SQL # do chủ sở hữu bảng và hàm cần phải giống nhau).
Solomon Rutzky

Câu trả lời:


5

Một chức năng không nhất thiết phải xác định hoặc không xác định. Có một số chức năng có thể xác định tùy thuộc vào cách chúng được sử dụng :

Các hàm sau không phải luôn luôn xác định, nhưng có thể được sử dụng trong các khung nhìn hoặc chỉ mục được lập chỉ mục trên các cột được tính khi chúng được chỉ định theo cách xác định.

CASTCONVERTlà những ví dụ như vậy. Dựa trên thử nghiệm mà bạn đã thực hiện cho đến nay, tôi nghĩ rằng thật công bằng khi nói rằng điều đó FORMATkhông phải lúc nào cũng mang tính quyết định, mặc dù là một hàm chuỗi. Nếu bạn muốn biết liệu đôi khi nó mang tính quyết định, kỹ thuật duy nhất tôi có thể nghĩ đến là thử đủ các cách khác nhau để gọi nó cho đến khi bạn hài lòng. Ví dụ, hãy xem xét FORMATnhư áp dụng cho số. Chỉ có mười loại đầu vào số khác nhau :

loại đầu vào số

Cũng có chín định dạng số khác nhau . Có thể cố gắng tạo các cột bền vững cho tất cả các kết hợp có thể. Một số mã để làm điều đó là dưới đây:

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;

Đây là một mẫu của đầu ra:

kiểm tra đầu ra mã

Tôi không thể có bất kỳ cột nào được thêm vào bảng cho một vài giá trị và văn hóa đầu vào. Tôi đã không thử triệt để tất cả các nền văn hóa có thể bởi vì tôi không thể tìm thấy danh sách của chúng trong SQL Server.

Tối thiểu có vẻ an toàn để kết luận rằng tài liệu liên quan đến tính xác định FORMATlà không chính xác, vì vậy tôi khuyên bạn nên gửi một mục kết nối cho nó.



1

Tôi không phải là người dùng thường xuyên của sqlserver, vì vậy tôi có thể bị nhầm, nhưng tôi đoán định dạng đó không phải là một hàm chuỗi. Theo tài liệu:

https://docs.microsoft.com/en-us/sql/t-sql/fifts/format-transact-sql

định dạng lấy kiểu ngày hoặc kiểu số làm đối số. Nếu tất cả những gì bạn muốn làm là lấy một phần của một ngày, bạn không thể sử dụng chức năng năm?

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

nếu bạn muốn một đại diện chuỗi:

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

1
Nó được liệt kê như là một hàm chuỗi trong tài liệu. i.stack.imgur.com/aj0T2.png
Martin Smith

1
@MartinSmith, thú vị. Cá nhân tôi thấy nó phản tác dụng trực quan và nó cũng trở nên không phù hợp về mặt logic với "Tất cả các hàm chuỗi dựng sẵn là xác định."
Lennart

@Lennart Tôi đánh giá cao sự thay thế cho ví dụ, nhưng ví dụ này không quan trọng.
SqlZim

1
@SqlZim, tôi đoán rằng ví dụ của bạn chỉ là một ví dụ nhưng tôi đã thêm một sự thay thế chỉ trong trường hợp. Tôi không chắc câu hỏi của bạn chính xác là gì, liệu định dạng có phải là hàm chuỗi hay không, liệu nó có xác định hay không, hoặc liệu tất cả những điều đó có được ghi lại không?
Lennart
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.