String.Format seperti fungsionalitas di T-SQL?

90

Saya mencari fungsi built-in / extended function di T-SQL untuk manipulasi string yang mirip dengan String.Formatmetode di .NET.

Jeff
sumber

Jawaban:

71

Jika Anda menggunakan SQL Server 2012 dan yang lebih baru, Anda dapat menggunakan FORMATMESSAGE. misalnya.

DECLARE @s NVARCHAR(50) = 'World';
DECLARE @d INT = 123;
SELECT FORMATMESSAGE('Hello %s, %d', @s, @d)
-- RETURNS 'Hello World, 123'

Lebih banyak contoh dari MSDN: FORMATMESSAGE

SELECT FORMATMESSAGE('Signed int %i, %d %i, %d, %+i, %+d, %+i, %+d', 5, -5, 50, -50, -11, -11, 11, 11);
SELECT FORMATMESSAGE('Signed int with leading zero %020i', 5);
SELECT FORMATMESSAGE('Signed int with leading zero 0 %020i', -55);
SELECT FORMATMESSAGE('Unsigned int %u, %u', 50, -50);
SELECT FORMATMESSAGE('Unsigned octal %o, %o', 50, -50);
SELECT FORMATMESSAGE('Unsigned hexadecimal %x, %X, %X, %X, %x', 11, 11, -11, 50, -50);
SELECT FORMATMESSAGE('Unsigned octal with prefix: %#o, %#o', 50, -50);
SELECT FORMATMESSAGE('Unsigned hexadecimal with prefix: %#x, %#X, %#X, %X, %x', 11, 11, -11, 50, -50);
SELECT FORMATMESSAGE('Hello %s!', 'TEST');
SELECT FORMATMESSAGE('Hello %20s!', 'TEST');
SELECT FORMATMESSAGE('Hello %-20s!', 'TEST');
SELECT FORMATMESSAGE('Hello %20s!', 'TEST');

CATATAN:

  • Tidak berdokumen pada tahun 2012
  • Dibatasi hingga 2044 karakter
  • Untuk menghindari tanda%, Anda perlu menggandakannya.
  • Jika Anda mencatat kesalahan dalam acara yang diperpanjang, panggilan FORMATMESSAGEmuncul sebagai kesalahan (tidak berbahaya)
g2server
sumber
1
Jika Anda menggunakan SQL 2012, Anda dapat menggunakan fungsi FORMAT tanpa semua komplikasi di atas :)
Reversed Engineer
1
Ini seharusnya memiliki lebih banyak suara! Penemuan mengagumkan selalu dihindari karena diasumsikan hanya akan bekerja dengan built-in msg_number.
Lankymart
1
@Lankymart, benjolan! Saya setuju ini harus menjadi jawaban yang diterima: sederhana, built-in dan bekerja dengan baik.
Robert Synoradzki
5
@bijayk hanya menerima nama placeholder tertentu, misalnya,% s untuk string,% i untuk ints.
g2server
2
@lostmylogin Tidak ada string.Formatfungsi-gaya di T-SQL, ini adalah yang terdekat yang akan Anda dapatkan.
Ian Kemp
53

lihat xp_sprintf . contoh di bawah ini.

DECLARE @ret_string varchar (255)
EXEC xp_sprintf @ret_string OUTPUT, 
    'INSERT INTO %s VALUES (%s, %s)', 'table1', '1', '2'
PRINT @ret_string

Hasilnya terlihat seperti ini:

INSERT INTO table1 VALUES (1, 2)

Baru saja menemukan masalah dengan ukuran maksimal (255 karakter batas) string dengan ini sehingga ada fungsi alternatif yang dapat Anda gunakan:

create function dbo.fnSprintf (@s varchar(MAX), 
                @params varchar(MAX), @separator char(1) = ',')
returns varchar(MAX)
as
begin
declare @p varchar(MAX)
declare @paramlen int

set @params = @params + @separator
set @paramlen = len(@params)
while not @params = ''
begin
    set @p = left(@params+@separator, charindex(@separator, @params)-1)
    set @s = STUFF(@s, charindex('%s', @s), 2, @p)
    set @params = substring(@params, len(@p)+2, @paramlen)
end
return @s
end

Untuk mendapatkan hasil yang sama seperti di atas Anda memanggil fungsi sebagai berikut:

print dbo.fnSprintf('INSERT INTO %s VALUES (%s, %s)', 'table1,1,2', default)
Josh
sumber
7
Sebagai informasi, jika salah satu parameter Anda berisi koma, maka Anda kurang beruntung. Jika Anda kebetulan melewatinya secara tidak sengaja, Anda akan mengalami beberapa masalah untuk mencari tahu apa yang salah.
Kyle
15

Saya telah membuat fungsi yang ditentukan pengguna untuk meniru fungsionalitas string.format. Anda bisa menggunakannya.

stringformat-in-sql

Karthik DV
sumber
Saya suka solusi ini karena saya memiliki keberatan terhadap penggunaan xp_ functions / SPs dalam produksi. Saya menggunakan kode Anda sebagai basis dan mengizinkan penerusan pemisah, yang menghilangkan kekhawatiran tentang penggunaan koma dalam data.
Tim Friesen
4

Ada cara, tetapi ada batasannya. Anda bisa menggunakan FORMATMESSAGE()fungsinya. Ini memungkinkan Anda untuk memformat string menggunakan pemformatan yang mirip dengan printf()fungsi di C.

Namun, batasan terbesar adalah ini hanya akan bekerja dengan pesan di tabel sys.messages. Berikut artikel tentangnya: microsoft_library_ms186788

Sayang sekali tidak ada cara yang lebih mudah untuk melakukan ini, karena ada kalanya Anda ingin memformat string / varchar di database. Semoga Anda hanya ingin memformat string dengan cara standar dan dapat menggunakan sys.messagestabel.

Secara kebetulan, Anda juga bisa menggunakan RAISERROR()fungsi dengan tingkat keseriusan yang sangat rendah, dokumentasi untuk raiseerror bahkan menyebutkan melakukan ini, tetapi hasilnya hanya dicetak. Jadi Anda tidak akan dapat melakukan apa pun dengan nilai yang dihasilkan (dari apa yang saya pahami).

Semoga berhasil!

jj.
sumber
1
Pahami ini adalah jawaban lama tetapi asumsi tentang FORMATMESSAGE()salah, namun bisa dimengerti karena tidak terdokumentasi tetapi akan menerima string apa pun sebagai parameter pertama, lihat jawaban ini oleh @ g2server .
Lankymart
@Lankymart Anda benar - ini adalah jawaban lama. Kemampuan untuk menerima string tidak ditambahkan hingga SQL 2012.
jj.
3

T-sql mentah dibatasi untuk CHARINDEX (), PATINDEX (), REPLACE (), dan SUBSTRING () untuk manipulasi string. Tetapi dengan sql server 2005 dan yang lebih baru Anda dapat mengatur fungsi yang ditentukan pengguna yang berjalan di .Net, yang berarti menyiapkan string.format () UDF seharusnya tidak terlalu sulit.

Joel Coehoorn
sumber
2

Satu gagasan lagi.

Meskipun ini bukan solusi universal - ini sederhana dan berfungsi, setidaknya untuk saya :)

Untuk satu placeholder {0}:

create function dbo.Format1
(
    @String  nvarchar(4000),
    @Param0  sql_variant
)
returns nvarchar(4000)
as
begin
    declare @Null nvarchar(4) = N'NULL';

    return replace(@String, N'{0}', cast(isnull(@Param0, @Null) as nvarchar(4000)));    
end

Untuk dua placeholder {0} dan {1}:

create function dbo.Format2
(
    @String  nvarchar(4000),
    @Param0  sql_variant,
    @Param1  sql_variant
)
returns nvarchar(4000)
as
begin
    declare @Null nvarchar(4) = N'NULL';

    set @String = replace(@String, N'{0}', cast(isnull(@Param0, @Null) as nvarchar(4000)));
       return     replace(@String, N'{1}', cast(isnull(@Param1, @Null) as nvarchar(4000))); 
end

Untuk tiga placeholder {0}, {1} dan {2}:

create function dbo.Format3
(
    @String  nvarchar(4000),
    @Param0  sql_variant,
    @Param1  sql_variant,
    @Param2  sql_variant
)
returns nvarchar(4000)
as
begin
    declare @Null nvarchar(4) = N'NULL';

    set @String = replace(@String, N'{0}', cast(isnull(@Param0, @Null) as nvarchar(4000)));
    set @String = replace(@String, N'{1}', cast(isnull(@Param1, @Null) as nvarchar(4000))); 
       return     replace(@String, N'{2}', cast(isnull(@Param2, @Null) as nvarchar(4000)));
end

dan seterusnya...

Pendekatan semacam itu memungkinkan kita untuk menggunakan fungsi-fungsi ini dalam pernyataan SELECT dan dengan parameter nvarchar, number, bit, dan datetime datatypes.

Sebagai contoh:

declare @Param0 nvarchar(10) = N'IPSUM' ,
        @Param1 int          = 1234567  ,
        @Param2 datetime2(0) = getdate();

select dbo.Format3(N'Lorem {0} dolor, {1} elit at {2}', @Param0, @Param1, @Param2);  
Vadim Loboda
sumber
1

Saya pikir ada koreksi kecil saat menghitung posisi akhir.

Ini adalah fungsi yang benar

**>>**IF OBJECT_ID( N'[dbo].[FormatString]', 'FN' ) IS NOT NULL
DROP FUNCTION [dbo].[FormatString]
GO
/***************************************************
Object Name : FormatString
Purpose : Returns the formatted string.
Original Author : Karthik D V http://stringformat-in-sql.blogspot.com/
Sample Call:
SELECT dbo.FormatString ( N'Format {0} {1} {2} {0}', N'1,2,3' )
*******************************************/
CREATE FUNCTION [dbo].[FormatString](
    @Format NVARCHAR(4000) ,
    @Parameters NVARCHAR(4000)
)
RETURNS NVARCHAR(4000)
AS
BEGIN
    --DECLARE @Format NVARCHAR(4000), @Parameters NVARCHAR(4000) select @format='{0}{1}', @Parameters='hello,world'
    DECLARE @Message NVARCHAR(400), @Delimiter CHAR(1)
    DECLARE @ParamTable TABLE ( ID INT IDENTITY(0,1), Parameter VARCHAR(1000) )
    Declare @startPos int, @endPos int
    SELECT @Message = @Format, @Delimiter = ','**>>**

    --handle first parameter
     set @endPos=CHARINDEX(@Delimiter,@Parameters)
    if (@endPos=0 and @Parameters is not null) --there is only one parameter
        insert into @ParamTable (Parameter) values(@Parameters)
    else begin
        insert into @ParamTable (Parameter) select substring(@Parameters,0,@endPos)
    end

    while @endPos>0
    Begin
        --insert a row for each parameter in the 
        set @startPos = @endPos + LEN(@Delimiter)
        set @endPos = CHARINDEX(@Delimiter,@Parameters, @startPos)
        if (@endPos>0)
            insert into @ParamTable (Parameter) 
                select substring(@Parameters,@startPos,@endPos - @startPos)
            else
                insert into @ParamTable (Parameter) 
                select substring(@Parameters,@startPos,4000)            
    End

    UPDATE @ParamTable SET @Message = 
        REPLACE ( @Message, '{'+CONVERT(VARCHAR,ID) + '}', Parameter )
    RETURN @Message
END
Go
grant execute,references on dbo.formatString to public 
SP007
sumber
1

Ini versi saya. Dapat diperpanjang untuk mengakomodasi lebih banyak parameter dan dapat memperluas format berdasarkan jenis. Saat ini hanya tipe tanggal dan waktu yang diformat.

Contoh:

select dbo.FormatString('some string %s some int %s date %s','"abcd"',100,cast(getdate() as date),DEFAULT,DEFAULT)
select dbo.FormatString('some string %s some int %s date time %s','"abcd"',100,getdate(),DEFAULT,DEFAULT)

Keluaran:

some string "abcd" some int 100 date 29-Apr-2017
some string "abcd" some int 100 date time 29-Apr-2017 19:40

Fungsi:

create function dbo.FormatValue(@param sql_variant)
returns nvarchar(100)
begin
/*
Tejasvi Hegde, 29-April-2017
Can extend formatting here.
*/
    declare @result nvarchar(100)

    if (SQL_VARIANT_PROPERTY(@param,'BaseType') in ('date'))
    begin
       select @result = REPLACE(CONVERT(CHAR(11), @param, 106), ' ', '-')
    end
    else  if (SQL_VARIANT_PROPERTY(@param,'BaseType') in ('datetime','datetime2'))
    begin
       select @result = REPLACE(CONVERT(CHAR(11), @param, 106), ' ', '-')+' '+CONVERT(VARCHAR(5),@param,108)
    end
    else
    begin
       select @result = cast(@param as nvarchar(100))
    end
    return @result

/*
BaseType:
bigint
binary
char
date
datetime
datetime2
datetimeoffset
decimal
float
int
money
nchar
numeric
nvarchar
real
smalldatetime
smallint
smallmoney
time
tinyint
uniqueidentifier
varbinary
varchar
*/   

end;


create function dbo.FormatString(
    @format nvarchar(4000)
    ,@param1 sql_variant = null
    ,@param2 sql_variant = null
    ,@param3 sql_variant = null
    ,@param4 sql_variant = null
    ,@param5 sql_variant = null
    )
returns nvarchar(4000)
begin
/*
Tejasvi Hegde, 29-April-2017

select dbo.FormatString('some string value %s some int %s date %s','"abcd"',100,cast(getdate() as date),DEFAULT,DEFAULT)
select dbo.FormatString('some string value %s some int %s date time %s','"abcd"',100,getdate(),DEFAULT,DEFAULT)
*/

    declare @result nvarchar(4000)

    select @param1 = dbo.formatValue(@param1)
    ,@param2 = dbo.formatValue(@param2)
    ,@param3 = dbo.formatValue(@param3)
    ,@param4 = dbo.formatValue(@param4)
    ,@param5 = dbo.formatValue(@param5)

    select @param2 = cast(@param2 as nvarchar)
    EXEC xp_sprintf @result OUTPUT,@format , @param1, @param2, @param3, @param4, @param5

    return @result

end;
Tejasvi Hegde
sumber
Jawaban paling sederhana untuk SQL Server 2008+. Menjaga input sebagai parameter terpisah. Menggunakan fungsi xp_sprintf dan dapat diperpanjang dengan mudah. xp_sprintf - docs.microsoft.com/en-us/sql/relational-databases/…
Jeff Lewis
0

inilah yang saya temukan dengan eksperimen saya menggunakan built-in

FORMATMESSAGE ()

sp_addmessage @msgnum=50001,@severity=1,@msgText='Hello %s you are #%d',@replace='replace'
SELECT FORMATMESSAGE(50001, 'Table1', 5)

ketika Anda memanggil sp_addmessage, template pesan Anda disimpan ke dalam tabel sistem master.dbo.sysmessages (diverifikasi pada SQLServer 2000).

Anda harus mengelola sendiri penambahan dan penghapusan string template dari tabel, yang aneh jika yang Anda inginkan hanyalah menampilkan pesan cepat ke layar hasil.

Solusi yang disediakan oleh Kathik DV, terlihat menarik tetapi tidak berfungsi dengan SQL Server 2000, jadi saya mengubahnya sedikit, dan versi ini seharusnya berfungsi dengan semua versi SQL Server:

IF OBJECT_ID( N'[dbo].[FormatString]', 'FN' ) IS NOT NULL
    DROP FUNCTION [dbo].[FormatString]
GO
/***************************************************
Object Name : FormatString
Purpose : Returns the formatted string.
Original Author : Karthik D V http://stringformat-in-sql.blogspot.com/
Sample Call:
SELECT dbo.FormatString ( N'Format {0} {1} {2} {0}', N'1,2,3' )
*******************************************/
CREATE FUNCTION [dbo].[FormatString](
@Format NVARCHAR(4000) ,
@Parameters NVARCHAR(4000)
)
RETURNS NVARCHAR(4000)
AS
BEGIN
    --DECLARE @Format NVARCHAR(4000), @Parameters NVARCHAR(4000) select @format='{0}{1}', @Parameters='hello,world'
    DECLARE @Message NVARCHAR(400), @Delimiter CHAR(1)
    DECLARE @ParamTable TABLE ( ID INT IDENTITY(0,1), Parameter VARCHAR(1000) )
    Declare @startPos int, @endPos int
    SELECT @Message = @Format, @Delimiter = ','

    --handle first parameter
     set @endPos=CHARINDEX(@Delimiter,@Parameters)
    if (@endPos=0 and @Parameters is not null) --there is only one parameter
        insert into @ParamTable (Parameter) values(@Parameters)
    else begin
        insert into @ParamTable (Parameter) select substring(@Parameters,0,@endPos)
    end

    while @endPos>0
    Begin
        --insert a row for each parameter in the 
        set @startPos = @endPos + LEN(@Delimiter)
        set @endPos = CHARINDEX(@Delimiter,@Parameters, @startPos)
        if (@endPos>0)
            insert into @ParamTable (Parameter) select substring(@Parameters,@startPos,@endPos)
        else
            insert into @ParamTable (Parameter) select substring(@Parameters,@startPos,4000)            
    End

    UPDATE @ParamTable SET @Message = REPLACE ( @Message, '{'+CONVERT(VARCHAR,ID) + '}', Parameter )
    RETURN @Message
END
Go
    grant execute,references on dbo.formatString to public

Pemakaian:

print dbo.formatString('hello {0}... you are {1}','world,good')
--result: hello world... you are good
BraveNewMath
sumber
-1

Sebenarnya tidak ada fungsi bawaan yang mirip dengan string. Fungsi format .NET tersedia di SQL server.

Ada fungsi FORMATMESSAGE () di SQL server tetapi itu meniru fungsi printf () dari C bukan string. Fungsi format .NET.

SELECT FORMATMESSAGE('This is the %s and this is the %s.', 'first variable', 'second variable') AS Result
Brijesh Kumar Tripathi
sumber
-2

Tidak juga, tapi saya akan memeriksa beberapa artikel tentang penanganan string (antara lain) oleh "Phil Factor" (geddit?) Di Simple Talk.

Duncan Cerdas
sumber
-3

ini pendekatan yang buruk. Anda harus bekerja dengan dll perakitan, di mana akan melakukan hal yang sama untuk Anda dengan kinerja yang lebih baik.

pelegk1
sumber