让某人使用SQL Server函数,该函数给定一个模式和一个值,可以返回一个规范化的值
我正在用SQL2008R2编写一个函数,我可以给它一些参数,比如值varchar、模式varchar、分隔符char和填充符char。然后我想用模式'000.000.000.000'给值'22687',一个分隔符'。'填充将是'0',然后我希望函数将返回'000.000.022.687',是否有任何函数已经完成,可以这样做 大概是这样的:让某人使用SQL Server函数,该函数给定一个模式和一个值,可以返回一个规范化的值,sql,function,design-patterns,sql-server-2008-r2,Sql,Function,Design Patterns,Sql Server 2008 R2,我正在用SQL2008R2编写一个函数,我可以给它一些参数,比如值varchar、模式varchar、分隔符char和填充符char。然后我想用模式'000.000.000.000'给值'22687',一个分隔符'。'填充将是'0',然后我希望函数将返回'000.000.022.687',是否有任何函数已经完成,可以这样做 大概是这样的: DECLARE @valor VARCHAR(30) DECLARE @formato VARCHAR(30) DECLARE @separador CHAR
DECLARE @valor VARCHAR(30)
DECLARE @formato VARCHAR(30)
DECLARE @separador CHAR(1)
DECLARE @rellenarcon CHAR(1)
SELECT @valor = '22959'
SELECT @formato = '000.000.000.000'
SELECT @separador = '.'
SELECT @rellenarcon = '0'
DECLARE @n INTEGER
DECLARE @m INTEGER
DECLARE @i INTEGER
DECLARE @j INTEGER
SELECT @n = LEN(@formato)
SELECT @m = LEN(@valor)
SELECT @i = 1
SELECT @j = 1
DECLARE @res2 varchar(30)
SELECT @res2 = ''
SELECT @valor = REVERSE(@valor)
WHILE @i<=@n
BEGIN
if SUBSTRING(@formato,@i,1) <> @separador
begin
IF @j<=@m
BEGIN
SELECT @res2 = @res2 + SUBSTRING(@valor,@j,1)
SELECT @i=@i+1
SELECT @j=@j+1
END
ELSE
BEGIN
SELECT @res2 = @res2 + @rellenarcon
SELECT @i=@i+1
END
end
else
BEGIN
SELECT @res2 = @res2 + @separador
SELECT @i=@i+1
END
END
print reverse(@res2)
是从java到tsql的交叉代码,java中的原始代码是:
public static String formatear(String valor, String formato, char separator,
char fillWith, Map<Integer, String> params) {
int n = formato.length() - 1;
int m = valor.length() - 1;
int i = n;
int j = m;
StringBuilder res = new StringBuilder(formato);
for(; i >= 0; i--) {
if(res.charAt(i) != separator) {
if(j >= 0) {
res.deleteCharAt(i);
res.insert(i, valor.charAt(j--));
} else {
res.deleteCharAt(i);
res.insert(i, fillWith);
}
}
}
if(params != null) {
Set<Integer> keys = params.keySet();
for(Integer key : keys) {
i = key;
res.deleteCharAt(i);
res.insert(i, params.get(key));
}
}
return res.toString();
}
此查询将执行以下操作:
;with cteZeroPadded(Num) as
(
Select Right('000000000000' + '22687', 12)
)
,cteSplit as
(
Select SUBSTRING(Num, 1, 3) Col1
,SUBSTRING(Num, 4, 3) Col2
,SUBSTRING(Num, 7, 3) Col3
,SUBSTRING(Num, 10, 3) Col4
From cteZeroPadded
)
Select Col1 + '.' + Col2 + '.' + Col3 + '.' + Col4
From cteSplit
在SQLServer2005+中,可以将选项与递归
请参见上的演示,以下假设输入格式正确,例如,值不长于模式
declare @Pattern as VarChar(64) = '000.000.000.000';
declare @Fill as Char = '0';
declare @Value as VarChar(64) = '22687';
declare @False as Bit = 0;
declare @True as Bit = 1;
with Gargoyle as (
select @Pattern as Pattern, @Value as Value, Cast( '' as VarChar(64) ) as Buffer,
case when Right( @Pattern, 1 ) = @Fill then @True else @False end as Fill
union all
select
-- Always consume a character from the pattern.
Left( Pattern, Len( Pattern ) - 1 ),
-- Consume a character from the value if the pattern contains fill at the current position.
case
when Fill = @True and Value != '' then Left( Value, Len( Value ) - 1 )
else Value end,
-- Add the correct character to the buffer.
Cast( case when Fill = @True and Value != '' then Right( Value, 1 ) else Right( Pattern, 1 ) end + Buffer as VarChar(64) ),
-- Check the next pattern character for fill.
case
when Len( Pattern ) = 1 then @False
when Substring( Pattern, Len( Pattern ) - 1, 1 ) = @Fill then @True
else @False end
from Gargoyle
where Pattern != ''
)
select Buffer
from Gargoyle
where Pattern = '';
或者,作为一种功能:
create function dbo.PatternFill( @Pattern as VarChar(64), @Fill as Char, @Value as VarChar(64) )
returns VarChar(64)
as
begin
declare @Buffer as VarChar(64) = ''
declare @PatternChar as Char = Right( @Pattern, 1 )
declare @ValueChar as Char = Right( @Value, 1 )
while @Pattern != ''
begin
if @PatternChar = @Fill and @ValueChar != ''
begin
-- Replace a fill character with a value character.
select @Buffer = @ValueChar + @Buffer
if Len( @Value ) > 1
select @Value = Left( @Value, Len( @Value ) - 1 ), @ValueChar = Right( @Value, 1 )
else
select @ValueChar = '', @Value = ''
end
else
begin
-- Copy the pattern character.
select @Buffer = @PatternChar + @Buffer
end
if Len( @Pattern ) > 1
select @Pattern = Left( @Pattern, Len( @Pattern ) - 1 ), @PatternChar = Right( @Pattern, 1 )
else
select @PatternChar = '', @Pattern = ''
end
return @Buffer
end
go
declare @Result as VarChar(64)
declare @Count as Int = 1000000
declare @Start as DateTime = GetDate()
while @Count > 0
select @Result = dbo.PatternFill( '000.000.000.000', '0', '22687' ), @Count = @Count - 1
select @Result as [Result], DateDiff( ms, @Start, GetDate() ) as [Total ms]
我的笔记本上的1000000次迭代耗时151656ms,但它正忙着启动。这是一个简单的计时,不需要校正空循环或调用空函数所消耗的时间。什么会消耗这些数据?通常我会尽量避免在数据库端格式化这样的类型…合理的描述是:给定@Pattern='000.000.000'、@Fill='0'和@Value='22687',将@Pattern中的填充字符从右向左替换为@Value中的字符吗?分隔符似乎无关紧要。这是一段java代码,用于Birt中的报告,我需要对sql@AbeMiessler进行交叉转换。数据传回java应用程序时,您可以格式化吗?@AbeMiessler可能。。我只是在编写sql方面的代码,java应用程序是另一个程序员,我要问的是,因为sql中的这些东西可能很昂贵。这不需要@Pattern和@Separator作为输入。啊,的确如此。我被困在“如果这样怎么办”的问题上,其余的都失败了。我不知道如何让它充满活力……我是CTE的新手,让我试着去理解它。。哈哈,但它看起来非常令人印象深刻。@Artenation-只要将最后一部分更改为从石像鬼中选择*,你就会看到发生了什么。我感觉自己就像弗林的儿子一样,当他进入了特隆的世界。。非常感谢您接受HABOanswer。。再一次非常感谢你,我正在向我的工作团队展示你的代码@尽管速度很慢。。32秒,只有209.063行。。我那难看的代码在HABO的网站上运行了2到3秒
create function dbo.PatternFill( @Pattern as VarChar(64), @Fill as Char, @Value as VarChar(64) )
returns VarChar(64)
as
begin
declare @Buffer as VarChar(64) = ''
declare @PatternChar as Char = Right( @Pattern, 1 )
declare @ValueChar as Char = Right( @Value, 1 )
while @Pattern != ''
begin
if @PatternChar = @Fill and @ValueChar != ''
begin
-- Replace a fill character with a value character.
select @Buffer = @ValueChar + @Buffer
if Len( @Value ) > 1
select @Value = Left( @Value, Len( @Value ) - 1 ), @ValueChar = Right( @Value, 1 )
else
select @ValueChar = '', @Value = ''
end
else
begin
-- Copy the pattern character.
select @Buffer = @PatternChar + @Buffer
end
if Len( @Pattern ) > 1
select @Pattern = Left( @Pattern, Len( @Pattern ) - 1 ), @PatternChar = Right( @Pattern, 1 )
else
select @PatternChar = '', @Pattern = ''
end
return @Buffer
end
go
declare @Result as VarChar(64)
declare @Count as Int = 1000000
declare @Start as DateTime = GetDate()
while @Count > 0
select @Result = dbo.PatternFill( '000.000.000.000', '0', '22687' ), @Count = @Count - 1
select @Result as [Result], DateDiff( ms, @Start, GetDate() ) as [Total ms]