String.Formatähnliche Funktionalität in T-SQL?

88

Ich suche nach einer integrierten Funktion / erweiterten Funktion in T-SQL für die Zeichenfolgenmanipulation ähnlich der String.FormatMethode in .NET.

Jeff
quelle

Antworten:

69

Wenn Sie SQL Server 2012 und höher verwenden, können Sie verwenden FORMATMESSAGE. z.B.

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

Weitere Beispiele aus 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');

ANMERKUNGEN:

  • Undokumentiert im Jahr 2012
  • Begrenzt auf 2044 Zeichen
  • Um dem% -Zeichen zu entkommen, müssen Sie es verdoppeln.
  • Wenn Sie Fehler in erweiterten Ereignissen protokollieren, wird der Aufruf FORMATMESSAGEals (harmloser) Fehler angezeigt
g2server
quelle
1
Wenn Sie SQL 2012 verwenden, können Sie die FORMAT-Funktion ohne die oben genannten Komplikationen verwenden :)
Reversed Engineer
1
Dies sollte viel mehr Stimmen haben! Genialer Fund wird immer vermieden, da davon ausgegangen wird, dass er nur mit eingebautem funktioniert msg_number.
Lankymart
1
@ Lankaymart, Beule! Ich bin damit einverstanden, dass dies die akzeptierte Antwort sein sollte: einfach, eingebaut und hervorragend funktioniert.
Robert Synoradzki
5
@bijayk Es werden nur bestimmte Platzhalternamen akzeptiert, z. B.% s für Zeichenfolgen,% i für Ints.
g2server
2
@lostmylogin string.FormatIn T-SQL gibt es keine Funktionalität im Stil, dies ist die nächstgelegene, die Sie erhalten.
Ian Kemp
53

Schauen Sie sich xp_sprintf an . Beispiel unten.

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

Ergebnis sieht so aus:

INSERT INTO table1 VALUES (1, 2)

Ich habe gerade ein Problem mit der maximalen Größe (maximal 255 Zeichen) der Zeichenfolge gefunden, sodass Sie eine alternative Funktion verwenden können:

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

Um das gleiche Ergebnis wie oben zu erhalten, rufen Sie die Funktion wie folgt auf:

print dbo.fnSprintf('INSERT INTO %s VALUES (%s, %s)', 'table1,1,2', default)
Josh
quelle
7
Nur zu Ihrer Information, wenn einer Ihrer Parameter ein Komma enthält, haben Sie kein Glück. Wenn Sie versehentlich an einem vorbeikommen, werden Sie Probleme haben, herauszufinden, was schief gelaufen ist.
Kyle
15

Ich habe eine benutzerdefinierte Funktion erstellt, um die Funktion string.format nachzuahmen. Du kannst es benutzen.

stringformat-in-sql

Karthik DV
quelle
Ich mag diese Lösung, da ich Vorbehalte gegen die Verwendung von xp_-Funktionen / SPs in der Produktion habe. Ich habe Ihren Code als Basis verwendet und die Übergabe des Trennzeichens zugelassen, wodurch alle Bedenken hinsichtlich der Verwendung von Kommas in den Daten beseitigt werden.
Tim Friesen
4

Es gibt einen Weg, aber er hat seine Grenzen. Sie können die FORMATMESSAGE()Funktion verwenden. Sie können eine Zeichenfolge mit einer Formatierung formatieren, die der printf()Funktion in C ähnelt .

Die größte Einschränkung besteht jedoch darin, dass nur Nachrichten in der Tabelle sys.messages verwendet werden. Hier ist ein Artikel darüber: microsoft_library_ms186788

Es ist eine Schande, dass es keinen einfacheren Weg gibt, dies zu tun, da es Zeiten gibt, in denen Sie einen String / Varchar in der Datenbank formatieren möchten. Hoffentlich möchten Sie eine Zeichenfolge nur auf standardmäßige Weise formatieren und können die sys.messagesTabelle verwenden.

Zufälligerweise können Sie die RAISERROR()Funktion auch mit einem sehr geringen Schweregrad verwenden. In der Dokumentation für Raiseerror wird dies sogar erwähnt, aber die Ergebnisse werden nur gedruckt. Mit dem resultierenden Wert könnten Sie also nichts anfangen (soweit ich weiß).

Viel Glück!

jj.
quelle
1
Verstehen Sie, dass dies eine alte Antwort ist, aber die Annahme über FORMATMESSAGE()ist falsch, jedoch verständlich, da sie nicht dokumentiert ist, aber eine beliebige Zeichenfolge als ersten Parameter akzeptiert . Siehe diese Antwort von @ g2server .
Lankymart
@Lankymart Du bist richtig - das ist eine alte Antwort. Die Möglichkeit, eine Zeichenfolge zu akzeptieren, wurde erst in SQL 2012 hinzugefügt.
jj.
3

Raw t-sql ist für die Zeichenfolgenmanipulation auf CHARINDEX (), PATINDEX (), REPLACE () und SUBSTRING () beschränkt. Mit SQL Server 2005 und höher können Sie jedoch benutzerdefinierte Funktionen einrichten, die in .Net ausgeführt werden. Das Einrichten einer UDF für string.format () sollte daher nicht zu schwierig sein.

Joel Coehoorn
quelle
2

Noch eine Idee.

Obwohl dies keine universelle Lösung ist - es ist einfach und funktioniert zumindest für mich :)

Für einen Platzhalter {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

Für zwei Platzhalter {0} und {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

Für drei Platzhalter {0}, {1} und {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

und so weiter...

Ein solcher Ansatz ermöglicht es uns, diese Funktionen in der SELECT-Anweisung und mit Parametern der Datentypen nvarchar, number, bit und datetime zu verwenden.

Beispielsweise:

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
quelle
1

Ich denke, es gibt eine kleine Korrektur bei der Berechnung der Endposition.

Hier ist die richtige Funktion

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

Hier ist meine Version. Kann erweitert werden, um mehr Parameter aufzunehmen, und kann die Formatierung basierend auf dem Typ erweitern. Derzeit werden nur Datums- und Datums- / Uhrzeittypen formatiert.

Beispiel:

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)

Ausgabe:

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

Funktionen:

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
quelle
Einfachste Antwort für SQL Server 2008+. Hält Eingaben als separate Parameter. Verwendet die Funktion xp_sprintf und kann einfach erweitert werden. xp_sprintf - docs.microsoft.com/en-us/sql/relational-databases/…
Jeff Lewis
0

Folgendes habe ich bei meinen Experimenten mit dem eingebauten Gerät gefunden

FORMATMESSAGE () Funktion

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

Wenn Sie sp_addmessage aufrufen, wird Ihre Nachrichtenvorlage in der Systemtabelle master.dbo.sysmessages gespeichert (überprüft auf SQLServer 2000).

Sie müssen das Hinzufügen und Entfernen von Vorlagenzeichenfolgen aus der Tabelle selbst verwalten. Dies ist umständlich, wenn Sie nur eine kurze Nachricht an den Ergebnisbildschirm ausgeben möchten.

Die von Kathik DV bereitgestellte Lösung sieht interessant aus, funktioniert aber nicht mit SQL Server 2000, daher habe ich sie ein wenig geändert, und diese Version sollte mit allen Versionen von SQL Server funktionieren:

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

Verwendung:

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

Tatsächlich gibt es keine integrierte Funktion, die der Zeichenfolge ähnelt. Die Formatfunktion von .NET ist in SQL Server verfügbar.

Es gibt eine Funktion FORMATMESSAGE () in SQL Server, die jedoch die Funktion printf () von C nachahmt, nicht string.Format von .NET.

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

Nicht genau, aber ich würde einige der Artikel über String-Handling (unter anderem) von "Phil Factor" (geddit?) Auf Simple Talk lesen.

Duncan Smart
quelle
-3

Das ist ein schlechter Ansatz. Sie sollten mit Assembly-DLLs arbeiten, in denen Sie dasselbe mit besserer Leistung tun.

pelegk1
quelle