Tsql T-SQL中类似字符串格式的功能?

Tsql T-SQL中类似字符串格式的功能?,tsql,string,Tsql,String,我正在寻找T-SQL中用于字符串操作的内置函数/扩展函数,类似于.NET中的string.Format方法。原始T-SQL仅限于CHARINDEX()、PATINDEX()、REPLACE()和SUBSTRING()用于字符串操作。但是使用sql server 2005和更高版本,您可以设置在.Net中运行的用户定义函数,这意味着设置string.format()UDF应该不会太难。不完全如此,但我会在简单对话中查看“Phil Factor”(geddit?)对字符串的一些处理,但它也有其局限性

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

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

不完全如此,但我会在简单对话中查看“Phil Factor”(geddit?)对字符串的一些处理,但它也有其局限性。您可以使用
FORMATMESSAGE()
函数。它允许您使用类似于C中的
printf()
函数的格式设置字符串的格式

但是,最大的限制是它只能处理sys.messages表中的消息。这里有一篇关于它的文章:

很遗憾,没有更简单的方法来实现这一点,因为有时您需要在数据库中格式化string/varchar。希望您只希望以标准方式格式化字符串,并且可以使用
sys.messages

巧合的是,您还可以使用严重性非常低的
raiseerror()
函数,raiseerror的文档甚至提到了这样做,但结果只是打印出来的。因此,您将无法对结果值做任何事情(据我所知)

祝你好运

看一看。下面的例子

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)

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

更新:
此版本允许用户更改定界器

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

下面是我使用内置的

FORMATMESSAGE()函数

调用sp_addmessage时,消息模板将存储到系统表master.dbo.sysmessages中(在SQLServer2000上验证)

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

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

我认为在计算端部位置时有小的修正

下面是正确的函数

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

这是一个糟糕的方法。您应该使用程序集dll,在这些dll中,您也可以获得更好的性能。

还有一个想法

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

对于一个占位符{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、number、bit和datetime数据类型的参数

例如:

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

如果您使用的是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中的更多示例:

注:

  • 2012年未登记
  • 限制为2044个字符
  • 要避开%符号,需要将其加倍
  • 如果您正在扩展事件中记录错误,则调用
    FORMATMESSAGE
    将显示为(无害的)错误

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

      例如:

      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;
      

      目前这还不存在(当然你可以自己写)。它有一个openconnect错误:,在撰写本文时,它只有1票

      实际上没有类似字符串的内置函数。SQL server中提供了.NET的Format函数

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

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

      仅供参考如果您的任何参数包含逗号,那么您就不走运了。如果你碰巧通过了一个测试,你将很难找出哪里出了问题。我喜欢这个解决方案,因为我对在生产中使用xp_uu函数/SP有所保留。我使用您的代码作为基础,并允许传入分隔符,这消除了对数据中使用逗号的任何担心。如果您使用的是SQL 2012,则可以使用,而不会出现上述所有复杂情况:)这应该有更多的投票权!总是避免使用令人敬畏的查找,因为假设它只适用于内置的
      msg\u number
      @Lankymart,bump!我同意这应该是公认的答案:简单、内置且工作出色。@bijayk它只接受特定的占位符名称,例如,%s代表字符串,%I代表整数。@lostmylogin在T-SQL中没有
      string.Format
      -样式的功能,这是您能得到的最接近的答案。请理解,这是一个旧答案,但关于
      FORMATMESSAGE()
      的假设是不正确的,尽管可以理解,因为它没有文档记录,但它将接受任何字符串作为第一个参数,请参见。@Lankymart您是正确的-这是一个旧答案。直到SQL 2012才添加接受字符串的功能。SQL Server 2008+的最简单答案。将输入保持为单独的参数。使用xp_sprintf函数,易于扩展。xp_sprintf-
      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;
      
      SELECT FORMATMESSAGE('This is the %s and this is the %s.', 'first variable', 'second variable') AS Result