Szukam funkcji wbudowanej / rozszerzonej w T-SQL do manipulacji ciągami podobnymi do String.Format
metody w .NET.
Odpowiedzi:
Jeśli używasz programu SQL Server 2012 i nowszych wersji, możesz użyć FORMATMESSAGE
. na przykład.
DECLARE @s NVARCHAR(50) = 'World';
DECLARE @d INT = 123;
SELECT FORMATMESSAGE('Hello %s, %d', @s, @d)
-- RETURNS 'Hello World, 123'
Więcej przykładów z 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');
UWAGI:
FORMATMESSAGE
będzie (nieszkodliwe)msg_number
.
string.Format
T-SQL nie ma funkcji stylu, to jest najbliższa, jaką otrzymasz.
spójrz na xp_sprintf . przykład poniżej.
DECLARE @ret_string varchar (255)
EXEC xp_sprintf @ret_string OUTPUT,
'INSERT INTO %s VALUES (%s, %s)', 'table1', '1', '2'
PRINT @ret_string
Wynik wygląda następująco:
INSERT INTO table1 VALUES (1, 2)
Właśnie znalazłem problem z maksymalnym rozmiarem (limit 255 znaków) w ciągu, więc istnieje alternatywna funkcja, której możesz użyć:
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
Aby uzyskać taki sam wynik, jak powyżej, wywołaj funkcję w następujący sposób:
print dbo.fnSprintf('INSERT INTO %s VALUES (%s, %s)', 'table1,1,2', default)
Utworzyłem funkcję zdefiniowaną przez użytkownika, aby naśladować funkcjonalność string.format. Możesz tego użyć.
Jest sposób, ale ma on swoje ograniczenia. Możesz użyć FORMATMESSAGE()
funkcji. Pozwala sformatować ciąg przy użyciu formatowania podobnego do printf()
funkcji w C.
Jednak największym ograniczeniem jest to, że będzie działać tylko z wiadomościami w tabeli sys.messages. Oto artykuł na ten temat: microsoft_library_ms186788
Szkoda, że nie ma prostszego sposobu na zrobienie tego, ponieważ są chwile, kiedy chcesz sformatować ciąg / varchar w bazie danych. Mam nadzieję, że chcesz sformatować ciąg tylko w standardowy sposób i możesz użyć sys.messages
tabeli.
Przypadkowo możesz również użyć RAISERROR()
funkcji z bardzo niską istotnością, dokumentacja podniesienia błędu nawet wspomina o tym, ale wyniki są tylko drukowane. Więc nie byłbyś w stanie nic zrobić z uzyskaną wartością (z tego, co rozumiem).
Powodzenia!
FORMATMESSAGE()
jest błędne, jednak zrozumiałe, ponieważ jest nieudokumentowane, ale będzie przyjmować dowolny ciąg jako pierwszy parametr, zobacz tę odpowiedź od @ g2server .
Surowe t-sql jest ograniczone do CHARINDEX (), PATINDEX (), REPLACE () i SUBSTRING () do manipulacji na ciągach. Ale z sql server 2005 i późniejszymi możesz skonfigurować funkcje zdefiniowane przez użytkownika, które działają w .Net, co oznacza, że ustawienie string.format () UDF nie powinno być zbyt trudne.
Jeszcze jeden pomysł.
Chociaż nie jest to rozwiązanie uniwersalne - jest proste i działa, przynajmniej dla mnie :)
Dla jednego symbolu zastępczego {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
W przypadku dwóch symboli zastępczych {0} i {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
W przypadku trzech symboli zastępczych {0}, {1} i {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
i tak dalej...
Takie podejście pozwala nam używać tych funkcji w instrukcji SELECT oraz z parametrami typu nvarchar, number, bit i datetime.
Na przykład:
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);
Myślę, że przy obliczaniu pozycji końcowej jest mała korekta.
Oto poprawna funkcja
**>>**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
Oto moja wersja. Można rozszerzyć, aby pomieścić większą liczbę parametrów i rozszerzyć formatowanie w oparciu o typ. Obecnie formatowane są tylko typy daty i godziny.
Przykład:
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)
Wynik:
some string "abcd" some int 100 date 29-Apr-2017
some string "abcd" some int 100 date time 29-Apr-2017 19:40
Funkcje:
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;
oto, co znalazłem podczas moich eksperymentów z użyciem wbudowanego
FORMATMESSAGE ()
sp_addmessage @msgnum=50001,@severity=1,@msgText='Hello %s you are #%d',@replace='replace'
SELECT FORMATMESSAGE(50001, 'Table1', 5)
kiedy wywołujesz sp_addmessage, szablon wiadomości zostaje zapisany w tabeli systemowej master.dbo.sysmessages (zweryfikowany na SQLServer 2000).
Musisz samodzielnie zarządzać dodawaniem i usuwaniem ciągów szablonów z tabeli, co jest niewygodne, jeśli naprawdę chcesz tylko wyświetlić szybką wiadomość na ekranie wyników.
Rozwiązanie dostarczone przez Kathik DV wygląda interesująco, ale nie działa z SQL Server 2000, więc trochę je zmieniłem i ta wersja powinna działać ze wszystkimi wersjami 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
Stosowanie:
print dbo.formatString('hello {0}... you are {1}','world,good')
--result: hello world... you are good
W tej chwili tak naprawdę nie istnieje (chociaż możesz oczywiście napisać własne). Występuje dla niego błąd otwartego połączenia: https://connect.microsoft.com/SQLServer/Feedback/Details/3130221 , który w chwili pisania tego tekstu ma tylko 1 głos.
Właściwie nie ma wbudowanej funkcji podobnej do stringa. Funkcja formatowania .NET jest dostępna w serwerze SQL.
Istnieje funkcja FORMATMESSAGE () na serwerze SQL, ale naśladuje ona funkcję printf () w języku C, a nie funkcję string.Format w .NET.
SELECT FORMATMESSAGE('This is the %s and this is the %s.', 'first variable', 'second variable') AS Result