像T-SQL中的功能一样的String.Format吗?


89

我正在寻找T-SQL中的内置函数/扩展函数来进行类似于String.Format.NET中方法的字符串操作。

Answers:


70

如果您使用的是SQL Server 2012及更高版本,则可以使用FORMATMESSAGE。例如。

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

来自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');

笔记:

  • 2012年未记录
  • 限制为2044个字符
  • 要转义%符号,您需要将其加倍。
  • 如果您在扩展事件中记录错误,则调用FORMATMESSAGE将作为(无害)错误出现

1
如果您使用的是SQL 2012,则可以使用FORMAT函数,而无需进行上述所有复杂操作:)
反向工程师

1
这应该有更多的选票!总是避免使用Awesome find,因为假设它只能与内置一起使用msg_number
Lankymart

1
@Lankymart,撞!我同意这应该是公认的答案:简单,内置且出色地工作。
罗伯特·西诺拉兹基

5
@bijayk它仅接受特定的占位符名称,例如,%s表示字符串,%i表示整数。
g2server'8

2
@lostmylogin string.FormatT-SQL中没有-style功能,这是您获得的最接近的功能。
伊恩·坎普

53

看看xp_sprintf。下面的例子。

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

结果如下:

INSERT INTO table1 VALUES (1, 2)

刚发现与此有关的字符串的最大大小(上限为255个字符)有问题,因此可以使用替代功能

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

要获得与上述相同的结果,请按以下方式调用该函数:

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

7
仅供参考,如果您的任何参数包含逗号,那么您就不走运了。如果您碰巧偶然通过了一个,您将很难找出问题所在。
凯尔(Kyle)2012年

15

我创建了一个用户定义的函数来模仿string.format功能。您可以使用它。

SQL中的字符串格式


我喜欢这种解决方案,因为我反对在生产中使用xp_函数/ SP。我将您的代码用作基础,并允许传入定界符,从而消除了对数据中使用逗号的任何担忧。
蒂姆·弗里森

4

有一种方法,但是有其局限性。您可以使用该FORMATMESSAGE()功能。它允许您使用类似于printf()C中函数的格式来格式化字符串。

但是,最大的限制是它仅适用于sys.messages表中的消息。这是一篇关于它的文章: microsoft_library_ms186788

遗憾的是,没有一种更简单的方法可以执行此操作,因为有时您需要在数据库中格式化字符串/ varchar。希望您只希望以标准方式设置字符串格式,并可以使用sys.messages表。

巧合的是,您也可以使用RAISERROR()严重性非常低的函数,raiseerror的文档甚至提到这样做,但是只打印结果。因此,根据所获得的价值(根据我的理解),您将无法做任何事情。

祝好运!


1
明白了这是一个古老的答案,但假设对FORMATMESSAGE()不正确,但是可以理解的,因为它是未公开,但将接受任何字符串作为第一个参数,看到这个答案@ g2server
Lankymart'1

@ Lankymart您是正确的-这是一个旧答案。没有添加到接受字符串的能力,直到2012年的SQL
JJ。

3

原始t-sql限于CHARINDEX(),PATINDEX(),REPLACE()和SUBSTRING()进行字符串操作。但是,在sql server 2005及更高版本中,您可以设置在.Net中运行的用户定义函数,这意味着设置string.format()UDF应该不会太困难。


2

还有一个主意。

虽然这不是一个通用的解决方案,但它很简单且有效,至少对我而言:)

对于一个占位符{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

对于两个占位符{0}和{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

对于三个占位符{0},{1}和{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

等等...

这种方法允许我们在SELECT语句中使用这些函数,并使用nvarchar,数字,位和日期时间数据类型的参数。

例如:

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

我认为在计算终点位置时会有小的修正。

这是正确的功能

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

这是我的版本。可以扩展以容纳更多数量的参数,并可以根据类型扩展格式。当前仅格式化日期和日期时间类型。

例:

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)

输出:

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

功能:

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;

SQL Server 2008+的最简单答案。将输入保留为单独的参数。使用xp_sprintf函数,可以轻松扩展。xp_sprintf-docs.microsoft.com/zh-cn/sql/relational-databases/…–
杰夫·路易斯

0

这是我使用内置的实验发现的

FORMATMESSAGE()函数

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

当您调用sp_addmessage时,您的消息模板将存储在系统表master.dbo.sysmessages中(已在SQLServer 2000上验证)。

您必须自己管理从表中添加和删除模板字符串,如果您真正想要的只是在结果屏幕上输出一条快速消息,则这很尴尬。

Kathik DV提供的解决方案看起来很有趣,但不适用于SQL Server 2000,因此我对其进行了一些更改,并且此版本应适用于所有版本的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

用法:

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


-1

实际上没有类似string的内置函数.SQL Server中提供.NET的Format函数。

SQL Server中有一个函数FORMATMESSAGE(),但它模仿的是C的printf()函数,而不是string.NET的Format函数。

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

-2

不完全是,但是我会在Simple Talk上查看“ Phil Factor”(geddit?)中有关字符串处理的文章(以及其他内容)。


-3

这是不好的方法。您应该使用汇编dll,在其中可以为您提供更好的性能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.