2008-10-01 13 views

Respuesta

3

Raw t-sql está limitado a CHARINDEX(), PATINDEX(), REPLACE() y SUBSTRING() para la manipulación de cadenas. Pero con sql server 2005 y posterior puede configurar funciones definidas por el usuario que se ejecutan en .Net, lo que significa que la configuración de un string.format() UDF no debería ser demasiado difícil.

-1

No exactamente, pero me gustaría echar un vistazo a algunos de los articles en el manejo de cadenas (entre otras cosas) por "Factor de Phil" (geddit?) En Simple Talk.

3

Hay una manera, pero tiene sus limitaciones. Puede usar la función FORMATMESSAGE(). Le permite formatear una cadena con un formato similar a la función printf() en C.

Sin embargo, la mayor limitación es que solo funcionará con mensajes en la tabla sys.messages. Aquí hay un artículo al respecto: microsoft_library_ms186788

Es una lástima que no hay una manera más fácil de hacerlo, porque hay ocasiones en que desea formatear una cadena/varchar en la base de datos. Con suerte, solo busca formatear una cadena de forma estándar y puede usar la tabla sys.messages.

Coincidentemente, también puede usar la función RAISERROR() con una gravedad muy baja, la documentación para raiseerror incluso menciona hacerlo, pero los resultados solo se imprimen. Entonces no podrías hacer nada con el valor resultante (según tengo entendido).

¡Buena suerte!

+0

Comprenda que esta es una respuesta anterior, pero la suposición de que 'FORMATMESSAGE()' es incorrecta, aunque comprensible porque no está documentada, pero aceptará cualquier cadena como primer parámetro, consulte [esta respuesta] (http://stackoverflow.com/a/30260729/692942) por [@ g2server] (http://stackoverflow.com/users/2293226/g2server). – Lankymart

+0

@Lankymart Tiene razón; esta es una respuesta antigua. La capacidad de aceptar una cadena no se agregó hasta SQL 2012. –

46

eche un vistazo a xp_sprintf. ejemplo a continuación.

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

El resultado es el siguiente:

INSERT INTO table1 VALUES (1, 2) 

acaba de encontrar un problema con el tamaño máximo (255 límite de caracteres) de la cadena con este modo hay una alternative function puede utilizar:

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(@[email protected], 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 

Para obtener el mismo resultado que el anterior, llame a la función de la siguiente manera:

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

Solo un FYI si alguno de tus parámetros contiene una coma, entonces no tienes suerte. Si pasa uno por accidente, tendrá algunos problemas para descubrir qué salió mal. – Kyle

+0

problemas con unicode? Veo que te refieres a varchar, no a nvarchar ... – barrypicker

14

He creado una función definida por el usuario para imitar la funcionalidad de string.format. Puedes usarlo.

stringformat-in-sql

+0

Agradable. Gracias por hacer esto – NotMe

+0

Me gusta esta solución ya que tengo reservas contra el uso de xp_ funciones/SP en producción. Utilicé el código como base y permití el paso del delimitador, lo que elimina cualquier preocupación sobre las comas que se usan en los datos. –

0

aquí es lo que me encontré con mis experimentos utilizando la función incorporada

FORMATMESSAGE()

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

cuando llame sp_addmessage, su plantilla de mensaje se almacena en el sistema tabla master.dbo.sysmessages (verificado en SQLServer 2000).

Debe gestionar la adición y eliminación de las cadenas de plantillas de la tabla usted mismo, lo que es incómodo si todo lo que realmente desea es enviar un mensaje rápido a la pantalla de resultados.

La solución proporcionada por Kathik DV, se ve interesante, pero no funciona con SQL Server 2000, por lo que alteré un poco, y esta versión debería funcionar con todas las versiones 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 

Uso :

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

Creo que hay una pequeña corrección al calcular la posición final.

Aquí es correcto funcionamiento

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

este enfoque es malo. deberías trabajar con dll de ensamblaje, en el que harás lo mismo para ti con un mejor rendimiento.

1

Una idea más.

Aunque esto no es una solución universal - que es simple y funciona, al menos para mí :)

Por un marcador de posición {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 

Durante dos marcadores de posición {0} y { 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 

Por tres marcadores de posición {0}, {1} y {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 

y así sucesivamente ...

Este enfoque nos permite utilizar estas funciones en la instrucción SELECT y con los parámetros de los tipos de datos nvarchar, number, bit y datetime.

Por ejemplo:

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

Si está utilizando SQL Server 2012 y anteriormente, el primer argumento para FORMATMESSAGE puede ser una cadena. p.ej.

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

Para escapar del signo%, debe duplicarlo.

Más ejemplos 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'); 

NOTAS:

  • indocumentados en 2012
  • limitada a 2044 caracteres
  • Si está registrando errores en eventos prolongados, FORMATMESSAGE llamando viene como un error (inofensivo).
+1

Si está utilizando SQL 2012, puede usar la [función FORMATO] (https://msdn.microsoft.com/en-us/library/hh213505 (v = sql.110) .aspx) sin todas las complicaciones anteriores:) – DaveBoltman

+0

Oh, sí, ¡por supuesto que tienes razón! – DaveBoltman

+1

¡Esto debería tener mucho más votos! Siempre se ha evitado el descubrimiento impresionante porque se suponía que solo funcionaría con el * 'msg_number' * incorporado. – Lankymart

1

Aquí está mi versión. Puede ampliarse para acomodar más parámetros y ampliar el formato según el tipo.Actualmente, solo los tipos de fecha y fecha y hora están formateados.

Ejemplo:

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) 

de salida:

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

Funciones:

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; 
+0

Respuesta más simple para SQL Server 2008+. Mantiene las entradas como parámetros separados. Utiliza la función xp_sprintf y se puede ampliar fácilmente. xp_sprintf - https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/xp-sprintf-transact-sql –

Cuestiones relacionadas