更好的技术来修剪SQL Server中的前导零?

我已经使用了一段时间了:

SUBSTRING(str_col, PATINDEX('%[^0]%', str_col), LEN(str_col)) 

然而最近,我发现一个所有“0”字符像“00000000”的列的问题,因为它从来没有发现一个非“0”字符匹配。

我见过的另一种技术是使用TRIM

 REPLACE(LTRIM(REPLACE(str_col, '0', ' ')), ' ', '0') 

如果有embedded空格,则会出现问题,因为当空格变回“0”时,它们将变为“0”。

我试图避免一个标量的UDF。 在SQL Server 2005中,我发现UDF有很多性能问题。

 SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col)) 

你为什么不把这个值转换成INTEGER然后回到VARCHAR

 SELECT CAST(CAST('000000000' AS INTEGER) AS VARCHAR) -------- 0 

其他答案在这里没有考虑,如果你有全零(甚至一个零)。
一些总是默认空string为零,这是错误的,当它应该保持空白。
重新阅读原来的问题。 这回答了提问者想要的。

解决scheme#1:

 --This example uses both Leading and Trailing zero's. --Avoid losing those Trailing zero's and converting embedded spaces into more zeros. --I added a non-whitespace character ("_") to retain trailing zero's after calling Replace(). --Simply remove the RTrim() function call if you want to preserve trailing spaces. --If you treat zero's and empty-strings as the same thing for your application, -- then you may skip the Case-Statement entirely and just use CN.CleanNumber . DECLARE @WackadooNumber VarChar(50) = ' 0 0123ABC D0 '--'000'-- SELECT WN.WackadooNumber, CN.CleanNumber, (CASE WHEN WN.WackadooNumber LIKE '%0%' AND CN.CleanNumber = '' THEN '0' ELSE CN.CleanNumber END)[AllowZero] FROM (SELECT @WackadooNumber[WackadooNumber]) AS WN OUTER APPLY (SELECT RTRIM(RIGHT(WN.WackadooNumber, LEN(LTRIM(REPLACE(WN.WackadooNumber + '_', '0', ' '))) - 1))[CleanNumber]) AS CN --Result: "123ABC D0" 

解决scheme#2(带样本数据):

 SELECT O.Type, O.Value, Parsed.Value[WrongValue], (CASE WHEN CHARINDEX('0', T.Value) > 0--If there's at least one zero. AND LEN(Parsed.Value) = 0--And the trimmed length is zero. THEN '0' ELSE Parsed.Value END)[FinalValue], (CASE WHEN CHARINDEX('0', T.Value) > 0--If there's at least one zero. AND LEN(Parsed.TrimmedValue) = 0--And the trimmed length is zero. THEN '0' ELSE LTRIM(RTRIM(Parsed.TrimmedValue)) END)[FinalTrimmedValue] FROM ( VALUES ('Null', NULL), ('EmptyString', ''), ('Zero', '0'), ('Zero', '0000'), ('Zero', '000.000'), ('Spaces', ' 0 ABC '), ('Number', '000123'), ('AlphaNum', '000ABC123'), ('NoZero', 'NoZerosHere') ) AS O(Type, Value)--O is for Original. CROSS APPLY ( --This Step is Optional. Use if you also want to remove leading spaces. SELECT LTRIM(RTRIM(O.Value))[Value] ) AS T--T is for Trimmed. CROSS APPLY ( --From @CadeRoux's Post. SELECT SUBSTRING(O.Value, PATINDEX('%[^0]%', O.Value + '.'), LEN(O.Value))[Value], SUBSTRING(T.Value, PATINDEX('%[^0]%', T.Value + '.'), LEN(T.Value))[TrimmedValue] ) AS Parsed 

结果:

MikeTeeVee_SQL_Server_Remove_Leading_Zeros

概要:

你可以使用我以上的一次性删除前导零。
如果您打算重复使用它,请将其放置在内联表值函数(ITVF)中。
您对UDF性能问题的关注是可以理解的。
但是,这个问题只适用于全标量函数和多语句表函数。
使用ITVF是完全正确的。

我与我们的第三方数据库有同样的问题。
随着字母数字领域的许多进入没有领先的空间,当人类!
如果不清除缺失的前导零,这使得连接变得不可能。

结论:

除了删除前导零之外,您可能还想考虑在进行连接时用前导零填充您的修剪值。
更好的是,通过添加前导零来清理表中的数据,然后重build索引。
我认为这将是更快,更简单的方式。

 SELECT RIGHT('0000000000' + LTRIM(RTRIM(NULLIF(' 0A10 ', ''))), 10)--0000000A10 SELECT RIGHT('0000000000' + LTRIM(RTRIM(NULLIF('', ''))), 10)--NULL --When Blank. 

而不是一个空格replace0与一个'罕见的'空白字符,通常不应该在列的文本。 换行可能足够像这样的列。 然后你可以正常的LTrim,再用0代替特殊字符。

如果string完全由零组成,以下代码将返回“0”:

 CASE WHEN SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col)) = '' THEN '0' ELSE SUBSTRING(str_col, PATINDEX('%[^0]%', str_col+'.'), LEN(str_col)) END AS str_col 

这使得一个很好的function….

 DROP FUNCTION [dbo].[FN_StripLeading] GO CREATE FUNCTION [dbo].[FN_StripLeading] (@string VarChar(128), @stripChar VarChar(1)) RETURNS VarChar(128) AS BEGIN -- http://stackoverflow.com/questions/662383/better-techniques-for-trimming-leading-zeros-in-sql-server DECLARE @retVal VarChar(128), @pattern varChar(10) SELECT @pattern = '%[^'+@stripChar+']%' SELECT @retVal = CASE WHEN SUBSTRING(@string, PATINDEX(@pattern, @string+'.'), LEN(@string)) = '' THEN @stripChar ELSE SUBSTRING(@string, PATINDEX(@pattern, @string+'.'), LEN(@string)) END RETURN (@retVal) END GO GRANT EXECUTE ON [dbo].[FN_StripLeading] TO PUBLIC 

如果string是一个数字,则强制转换(值为int)将始终有效

尝试这个:

 replace(ltrim(replace(@str, '0', ' ')), ' ', '0') 

我的这个版本是阿沃工作的一个改编,增加了一点,以确保另外两个案例。

1)如果我们全部为0,我们应该返回数字0。

2)如果我们有一个空白,我们仍然应该返回一个空白字符。

 CASE WHEN PATINDEX('%[^0]%', str_col + '.') > LEN(str_col) THEN RIGHT(str_col, 1) ELSE SUBSTRING(str_col, PATINDEX('%[^0]%', str_col + '.'), LEN(str_col)) END 
 replace(ltrim(replace(Fieldname.TableName, '0', '')), '', '0') 

Thomas G的build议为我们的需要工作。

在我们的例子中,字段已经是string了,只有前面的零需要被修剪。 大部分都是数字,但有时会有字母,所以以前的INT转换会崩溃。