String.Format come funzionalità in T-SQL?


91

Sto cercando una funzione incorporata / funzione estesa in T-SQL per la manipolazione delle stringhe simile al String.Formatmetodo in .NET.

Risposte:


72

Se utilizzi SQL Server 2012 e versioni successive, puoi utilizzare FORMATMESSAGE. per esempio.

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

Altri esempi da 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');

APPUNTI:

  • Non documentato nel 2012
  • Limitato a 2044 caratteri
  • Per sfuggire al segno%, devi raddoppiarlo.
  • Se stai registrando errori in eventi estesi, la chiamata FORMATMESSAGEsi presenta come un errore (innocuo)

1
Se stai usando SQL 2012, puoi usare la funzione FORMAT senza tutte le complicazioni di cui sopra :)
Reversed Engineer

1
Questo dovrebbe avere molti più voti! Una scoperta fantastica viene sempre evitata perché si presume che funzioni solo con built-in msg_number.
user692942

1
@Lankymart, bump! Sono d'accordo che questa dovrebbe essere la risposta accettata: semplice, integrata e funzionante magnificamente.
Robert Synoradzki,

5
@bijayk accetta solo nomi di segnaposto specifici, ad esempio% s per le stringhe,% i per gli int.
g2server

2
@lostmylogin Non ci sono string.Formatfunzionalità in stile in T-SQL, questa è la più vicina che otterrai.
Ian Kemp

54

dai un'occhiata a xp_sprintf . esempio sotto.

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

Il risultato è simile a questo:

INSERT INTO table1 VALUES (1, 2)

Ho appena trovato un problema con la dimensione massima (limite di 255 caratteri) della stringa con questo, quindi c'è una funzione alternativa che puoi usare:

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

Per ottenere lo stesso risultato di cui sopra, chiama la funzione come segue:

print dbo.fnSprintf('INSERT INTO %s VALUES (%s, %s)', 'table1,1,2', default)

7
Solo un FYI se uno qualsiasi dei tuoi parametri contiene una virgola, sei sfortunato. Se ti capita di passarne uno per sbaglio, avrai dei problemi a capire cosa è andato storto.
Kyle

16

Ho creato una funzione definita dall'utente per imitare la funzionalità string.format. Puoi usarlo.

stringformat-in-sql

AGGIORNAMENTO:
questa versione consente all'utente di modificare il delimitatore.

-- DROP function will loose the security settings.
IF object_id('[dbo].[svfn_FormatString]') IS NOT NULL
    DROP FUNCTION [dbo].[svfn_FormatString]
GO

CREATE FUNCTION [dbo].[svfn_FormatString]
(
    @Format NVARCHAR(4000),
    @Parameters NVARCHAR(4000),
    @Delimiter CHAR(1) = ','
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
    /*
        Name: [dbo].[svfn_FormatString]
        Creation Date: 12/18/2020

        Purpose: Returns the formatted string (Just like in C-Sharp)

        Input Parameters:   @Format         = The string to be Formatted
                            @Parameters     = The comma separated list of parameters
                            @Delimiter      = The delimitter to be used in the formatting process

        Format:             @Format         = N'Hi {0}, Welcome to our site {1}. Thank you {0}'
                            @Parameters     = N'Karthik,google.com'
                            @Delimiter      = ','           
        Examples:
            SELECT dbo.svfn_FormatString(N'Hi {0}, Welcome to our site {1}. Thank you {0}', N'Karthik,google.com', default)
            SELECT dbo.svfn_FormatString(N'Hi {0}, Welcome to our site {1}. Thank you {0}', N'Karthik;google.com', ';')
    */
    DECLARE @Message NVARCHAR(400)
    DECLARE @ParamTable TABLE ( Id INT IDENTITY(0,1), Paramter VARCHAR(1000))

    SELECT @Message = @Format

    ;WITH CTE (StartPos, EndPos) AS
    (
        SELECT 1, CHARINDEX(@Delimiter, @Parameters)
        UNION ALL
        SELECT EndPos + (LEN(@Delimiter)), CHARINDEX(@Delimiter, @Parameters, EndPos + (LEN(@Delimiter)))
        FROM CTE
        WHERE EndPos > 0
    )

    INSERT INTO @ParamTable ( Paramter )
    SELECT
        [Id] = SUBSTRING(@Parameters, StartPos, CASE WHEN EndPos > 0 THEN EndPos - StartPos ELSE 4000 END )
    FROM CTE

    UPDATE @ParamTable 
    SET 
        @Message = REPLACE(@Message, '{'+ CONVERT(VARCHAR, Id) + '}', Paramter )

    RETURN @Message
END

1
Mi piace questa soluzione poiché ho delle riserve contro l'utilizzo di xp_ functions / SPs in produzione. Ho usato il tuo codice come base e ho consentito il passaggio del delimitatore, che elimina ogni preoccupazione per le virgole utilizzate nei dati.
Tim Friesen

4

C'è un modo, ma ha i suoi limiti. Puoi usare la FORMATMESSAGE()funzione. Ti consente di formattare una stringa utilizzando una formattazione simile aprintf() funzione in C.

Tuttavia, il limite maggiore è che funzionerà solo con i messaggi nella tabella sys.messages. Ecco un articolo a riguardo: microsoft_library_ms186788

È un peccato che non ci sia un modo più semplice per farlo, perché ci sono momenti in cui si desidera formattare una stringa / varchar nel database. Si spera che tu stia solo cercando di formattare una stringa in modo standard e puoi usare la sys.messagestabella.

Per coincidenza, potresti anche usare la RAISERROR()funzione con un livello di gravità molto basso, la documentazione di raiseerror menziona anche questa operazione, ma i risultati vengono solo stampati. Quindi non saresti in grado di fare nulla con il valore risultante (da quello che ho capito).

In bocca al lupo!


1
Comprendi che questa è una vecchia risposta ma l'ipotesi a riguardo FORMATMESSAGE()non è corretta, comunque comprensibile perché non è documentata ma accetterà qualsiasi stringa come primo parametro, vedi questa risposta di @ g2server .
user692942

@Lankymart Hai ragione - questa è una vecchia risposta. La capacità di accettare una stringa non è stata aggiunta fino a SQL 2012.
jj.

3

Il t-sql grezzo è limitato a CHARINDEX (), PATINDEX (), REPLACE () e SUBSTRING () per la manipolazione delle stringhe. Ma con sql server 2005 e versioni successive è possibile impostare funzioni definite dall'utente che vengono eseguite in .Net, il che significa che impostare una UDF string.format () non dovrebbe essere troppo difficile.


2

Un'altra idea.

Anche se questa non è una soluzione universale, è semplice e funziona, almeno per me :)

Per un segnaposto {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

Per due segnaposto {0} e {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

Per tre segnaposto {0}, {1} e {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

e così via...

Un tale approccio ci consente di utilizzare queste funzioni nell'istruzione SELECT e con i parametri dei tipi di dati nvarchar, number, bit e datetime.

Per esempio:

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);  

1

Penso che ci sia una piccola correzione durante il calcolo della posizione finale.

Ecco la funzione corretta

**>>**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 

1

Ecco la mia versione. Può essere esteso per contenere un numero maggiore di parametri e può estendere la formattazione in base al tipo. Attualmente vengono formattati solo i tipi data e data / ora.

Esempio:

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)

Produzione:

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

Funzioni:

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;

Risposta più semplice per SQL Server 2008+. Mantiene gli input come parametri separati. Utilizza la funzione xp_sprintf e può essere estesa facilmente. xp_sprintf - docs.microsoft.com/en-us/sql/relational-databases/…
Jeff Lewis

0

ecco cosa ho trovato con i miei esperimenti utilizzando il built-in

Funzione FORMATMESSAGE ()

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

quando si richiama sp_addmessage, il modello di messaggio viene memorizzato nella tabella di sistema master.dbo.sysmessages (verificata su SQLServer 2000).

È necessario gestire da soli l'aggiunta e la rimozione delle stringhe del modello dalla tabella, il che è imbarazzante se tutto ciò che si desidera veramente è visualizzare un messaggio rapido nella schermata dei risultati.

La soluzione fornita da Kathik DV sembra interessante ma non funziona con SQL Server 2000, quindi l'ho modificata un po 'e questa versione dovrebbe funzionare con tutte le versioni di 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

Utilizzo:

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


0

In realtà non esiste una funzione incorporata simile alla funzione string.Format di .NET è disponibile in SQL Server.

C'è una funzione FORMATMESSAGE () in SQL server ma imita la funzione printf () di C e non la funzione string.Format di .NET.

SELECT FORMATMESSAGE('This is the %s and this is the %s.', 'first variable', 'second variable') AS Result

-2

Non esattamente, ma vorrei controllare alcuni degli articoli sulla gestione delle stringhe (tra le altre cose) di "Phil Factor" (geddit?) Su Simple Talk.


-3

questo è un cattivo approccio. dovresti lavorare con le dll di assembly, in cui faranno lo stesso per te con prestazioni migliori.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.