Я ищу встроенную функцию / расширенную функцию в T-SQL для обработки строк, аналогичную String.Format
методу в .NET.
Ответы:
Если вы используете 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');
НОТЫ:
FORMATMESSAGE
воспринимается как (безвредная) ошибкаmsg_number
.
string.Format
T-SQL нет функциональности стиля-стиля, это самое близкое из возможных.
взгляните на 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)
Я создал пользовательскую функцию для имитации функциональности 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()
функцию. Он позволяет форматировать строку, используя форматирование, аналогичное printf()
функции в C.
Однако самым большим ограничением является то, что он будет работать только с сообщениями в таблице sys.messages. Вот статья об этом: microsoft_library_ms186788
Жаль, что нет более простого способа сделать это, потому что бывают случаи, когда вы хотите отформатировать строку / varchar в базе данных. Надеюсь, вы только хотите отформатировать строку стандартным способом и можете использовать sys.messages
таблицу.
По совпадению, вы также можете использовать RAISERROR()
функцию с очень низким уровнем серьезности, в документации по raiseerror даже упоминается об этом, но результаты только распечатываются. Таким образом, вы не сможете ничего сделать с полученным значением (насколько я понимаю).
Удачи!
FORMATMESSAGE()
неверно, однако понятно , потому что он не документирован , но он будет принимать любую строку в качестве первого параметра, см этого ответа на @ g2server .
Необработанный t-sql ограничен функциями CHARINDEX (), PATINDEX (), REPLACE () и SUBSTRING () для обработки строк. Но с sql server 2005 и более поздними версиями вы можете настроить определяемые пользователем функции, которые выполняются в .Net, а это означает, что настройка UDF string.format () не должна быть слишком сложной.
Еще одна идея.
Хотя это не универсальное решение - оно простое и работает, по крайней мере, у меня :)
Для одного заполнителя {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);
Я думаю, есть небольшая поправка при расчете конечного положения.
Вот правильная функция
**>>**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
Вот моя версия. Может быть расширен для размещения большего количества параметров и может расширять форматирование в зависимости от типа. В настоящее время форматируются только типы date и datetime.
Пример:
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;
вот что я обнаружил в своих экспериментах с использованием встроенного
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
На данный момент этого действительно не существует (хотя вы, конечно, можете написать свое собственное). Для этого есть ошибка открытого подключения: https://connect.microsoft.com/SQLServer/Feedback/Details/3130221 , которая на момент написания этой статьи имеет всего 1 голос.
На самом деле встроенной функции, аналогичной строковой, нет. Функция форматирования .NET доступна в SQL-сервере.
В SQL-сервере есть функция FORMATMESSAGE (), но она имитирует функцию printf () языка C, а не функцию string.Format .NET.
SELECT FORMATMESSAGE('This is the %s and this is the %s.', 'first variable', 'second variable') AS Result
Не совсем так, но я бы посмотрел некоторые статьи по обработке строк (среди прочего), написанные "Phil Factor" (geddit?) На Simple Talk.