String.Format comme une fonctionnalité dans T-SQL?

89

Je recherche une fonction intégrée / une fonction étendue dans T-SQL pour la manipulation de chaînes similaire à la String.Formatméthode dans .NET.

Jeff
la source

Réponses:

70

Si vous utilisez SQL Server 2012 et versions ultérieures, vous pouvez utiliser FORMATMESSAGE. par exemple.

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

Plus d'exemples de 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');

REMARQUES:

  • Non documenté en 2012
  • Limité à 2044 caractères
  • Pour échapper au signe%, vous devez le doubler.
  • Si vous enregistrez des erreurs dans des événements étendus, l'appel FORMATMESSAGEapparaît comme une erreur (inoffensive)
g2server
la source
1
Si vous utilisez SQL 2012, vous pouvez utiliser la fonction FORMAT sans toutes les complications ci-dessus :)
Reversed Engineer
1
Cela devrait avoir beaucoup plus de votes! Une trouvaille impressionnante toujours évitée car supposée que cela ne fonctionnerait qu'avec des fichiers intégrés msg_number.
Lankymart
1
@Lankymart, bosse! Je suis d'accord que cela devrait être la réponse acceptée: simple, intégrée et fonctionnant à merveille.
Robert Synoradzki
5
@bijayk il n'accepte que des noms d'espace réservé spécifiques, par exemple,% s pour les chaînes,% i pour les entiers.
g2server
2
@lostmylogin Il n'y a pas de string.Formatfonctionnalité de style dans T-SQL, c'est la plus proche que vous obtiendrez.
Ian Kemp
53

jetez un œil à xp_sprintf . exemple ci-dessous.

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

Le résultat ressemble à ceci:

INSERT INTO table1 VALUES (1, 2)

Je viens de trouver un problème avec la taille maximale (limite de 255 caractères) de la chaîne, il existe donc une fonction alternative que vous pouvez utiliser:

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

Pour obtenir le même résultat que ci-dessus, vous appelez la fonction comme suit:

print dbo.fnSprintf('INSERT INTO %s VALUES (%s, %s)', 'table1,1,2', default)
Josh
la source
7
Juste un FYI si l'un de vos paramètres contient une virgule, vous n'avez pas de chance. Si vous en passez un par accident, vous aurez du mal à comprendre ce qui n'a pas fonctionné.
Kyle
15

J'ai créé une fonction définie par l'utilisateur pour imiter la fonctionnalité string.format. Tu peux l'utiliser.

stringformat-in-sql

Karthik DV
la source
J'aime cette solution car j'ai des réserves contre l'utilisation des fonctions xp_ / SP en production. J'ai utilisé votre code comme base et autorisé le passage du délimiteur, ce qui élimine toute préoccupation concernant les virgules utilisées dans les données.
Tim Friesen
4

Il existe un moyen, mais il a ses limites. Vous pouvez utiliser la FORMATMESSAGE()fonction. Il vous permet de formater une chaîne en utilisant un formatage similaire à la printf()fonction en C.

Cependant, la plus grande limitation est qu'elle ne fonctionnera qu'avec les messages de la table sys.messages. Voici un article à ce sujet: microsoft_library_ms186788

C'est un peu dommage qu'il n'y ait pas de moyen plus simple de le faire, car il y a des moments où vous voulez formater une chaîne / varchar dans la base de données. J'espère que vous cherchez uniquement à formater une chaîne de manière standard et que vous pouvez utiliser la sys.messagestable.

Par coïncidence, vous pouvez également utiliser la RAISERROR()fonction avec une gravité très faible, la documentation de riseerror mentionne même de le faire, mais les résultats ne sont imprimés. Vous ne pourriez donc rien faire avec la valeur résultante (d'après ce que je comprends).

Bonne chance!

jj.
la source
1
Comprenez que c'est une vieille réponse, mais l'hypothèse à propos de FORMATMESSAGE()est incorrecte, cependant compréhensible car elle n'est pas documentée, mais elle acceptera n'importe quelle chaîne comme premier paramètre, voir cette réponse par @ g2server .
Lankymart
@Lankymart Vous avez raison - c'est une vieille réponse. La possibilité d'accepter une chaîne n'a été ajoutée qu'à SQL 2012.
jj.
3

Le t-sql brut est limité à CHARINDEX (), PATINDEX (), REPLACE () et SUBSTRING () pour la manipulation de chaînes. Mais avec SQL Server 2005 et les versions ultérieures, vous pouvez configurer des fonctions définies par l'utilisateur qui s'exécutent dans .Net, ce qui signifie que la configuration d'un UDF string.format () ne devrait pas être trop difficile.

Joël Coehoorn
la source
2

Encore une idée.

Bien que ce ne soit pas une solution universelle - c'est simple et fonctionne, du moins pour moi :)

Pour un espace réservé {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

Pour deux espaces réservés {0} et {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

Pour trois espaces réservés {0}, {1} et {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

etc...

Une telle approche nous permet d'utiliser ces fonctions dans l'instruction SELECT et avec des paramètres de types de données nvarchar, number, bit et datetime.

Par exemple:

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
la source
1

Je pense qu'il y a une petite correction lors du calcul de la position finale.

Voici la fonction correcte

**>>**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
la source
1

Voici ma version. Peut être étendu pour accueillir plus de paramètres et peut étendre la mise en forme en fonction du type. Actuellement, seuls les types date et date / heure sont formatés.

Exemple:

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)

Production:

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

Les fonctions:

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
la source
La réponse la plus simple pour SQL Server 2008+. Conserve les entrées en tant que paramètres séparés. Utilise la fonction xp_sprintf et peut être étendue facilement. xp_sprintf - docs.microsoft.com/en-us/sql/relational-databases/…
Jeff Lewis
0

voici ce que j'ai trouvé avec mes expériences en utilisant le

Fonction FORMATMESSAGE ()

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

lorsque vous appelez sp_addmessage, votre modèle de message est stocké dans la table système master.dbo.sysmessages (vérifiée sur SQLServer 2000).

Vous devez gérer vous-même l'ajout et la suppression des chaînes de modèle de la table, ce qui est gênant si tout ce que vous voulez vraiment est d'afficher un message rapide sur l'écran des résultats.

La solution fournie par Kathik DV, semble intéressante mais ne fonctionne pas avec SQL Server 2000, donc je l'ai un peu modifiée, et cette version devrait fonctionner avec toutes les versions de 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

Usage:

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

En fait, il n'y a pas de fonction intégrée similaire à string.Format fonction de .NET est disponible dans SQL Server.

Il existe une fonction FORMATMESSAGE () dans le serveur SQL mais elle imite la fonction printf () de C et non la fonction string.Format de .NET.

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

Pas exactement, mais je consulterais certains des articles sur la gestion des chaînes (entre autres) de "Phil Factor" (geddit?) Sur Simple Talk.

Duncan Smart
la source
-3

c'est une mauvaise approche. vous devriez travailler avec des DLL d'assemblage, qui feront de même pour vous avec de meilleures performances.

pelegk1
la source