[英]How can I get only numbers from a string as a computed column in SQL Server with no leading zeroes?
背景
目前我有一个函数只从字符串中获取数字(没有前导零)(让我们调用两个变量@alphaNumeric
和@strippedNumber
)。
事实证明,在我查询的表上预先计算@strippedNumber
比使用我的函数动态计算它更有效(让我们称之为dbo.fnFormatNumeric
)。
设置我的计算列我尝试如下:
ALTER TABLE dbo.Data
ADD StrippedNumber AS CONVERT(BIGINT, dbo.fnFormatNumeric(AlphaNumeric))
这在转换大量数据(大约25,000,000+行)方面非常有效。
尝试升级我的数据库时出现问题 (我们删除并重新创建所有功能)。 所以我试图将该函数排除在外或被重新创建。
错误。 现在我无法安装新数据库,因为它依赖于尚未创建的功能。
理想的场景
我希望能够在不使用函数的情况下从字符串中选择字符串中的所有数字作为计算列。
研究
Sql Authority博客建议使用一个函数来获取数值, 这个答案在SO引用上。 这不是一件好事,因为一个功能会给我带来麻烦。
关于SO的另一个答案建议使用LEFT
和PATINDEX
但这只会得到第一组数字而不是字符串中的所有数字。
关于SO的这个问题并不好,因为它使用ISNUMERIC
只获取所有数字都是数字的字符串。
我找到了一篇博文 ,他们使用PATINDEX
从字符串中获取数字,但这是假设所有数字都在一起。
投入和预期产出:
@alphaNumeric => @strippedNumber
-----------------------------------
FXADJ011016CR => 11016
15-June-2016 => 152016
708014 => 708014
FXRWECTB => (empty string)
现有功能:
Input @alphaNumeric varchar(255)
DECLARE @strtoCheckLength Int,
@strCount Int,
@code Int,
@StrippedNumber varchar(255)
-- Get and set length and loop variables
Set @strtoCheckLength = Len(@alphaNumeric)
Set @strCount = (0)
Set @StrippedNumber = ''
-- Make sure we only include Numerics
While @strCount <= @strtoCheckLength
Begin
set @code = Ascii(SubString(@alphaNumeric, @strCount, 1))
If (@code between 48 and 57)
Begin
set @StrippedNumber = @StrippedNumber + Substring(@alphaNumeric, @strCount, 1)
End
Set @strCount = (@strCount + 1)
End
-- Remove Leading Zeros
While (Len(@StrippedNumber) > 0) And (Left(@StrippedNumber, 1) = '0')
Begin
Set @StrippedNumber = Right(@StrippedNumber, Len(@StrippedNumber) - 1)
End
Return @StrippedNumber
希望这段代码可以帮助您定义计算列。
本质上,数字表用于通过索引来分解字符串,然后查询将连接的输出强制转换为bigint以在重新转换为varchar之前删除前导零(255)
在生产数据库中,我建议预先定义和填充数字表。 关于如何在www.SqlServerCentral.com上使用它们有很多讨论
--set up a numbers table
select top 50 n=identity(int,1,1) into #temp_numbers from syscolumns
/*
FXADJ011016CR => 11016
15June2016 => 152016
708014 => 708014
FXRWECTB => Empty String
*/
declare @input varchar(50) = 'FXADJ011016CR'
declare @output varchar(50)
select isnull(cast(cast((
select numericValue as [text()] from (
select substring(@input, t.n, 1) as numericValue
from #temp_numbers t
where isnumeric(substring(@input, t.n, 1))=1
) tblResults for xml path('')
) as bigint) as varchar(255)),'')
drop table #temp_numbers
你可以用它
DECLARE @SampleData AS TABLE
(
Value varchar(100)
)
INSERT INTO @SampleData
VALUES ('FXADJ011016CR'),('15June2016'),
('708014 '), ('FXRWECTB ')
DECLARE @RegexNonNumber VARCHAR(30) = '%[^0-9]%'
;WHILE (EXISTS (SELECT 1 FROM @SampleData sd WHERE PatIndex(@RegexNonNumber, sd.[Value]) > 0))
BEGIN
UPDATE @SampleData
SET
[Value] = Stuff([Value], PatIndex(@RegexNonNumber, [Value]), 1, '')
WHERE PatIndex(@RegexNonNumber, [Value]) > 0
END
SELECT * FROM @SampleData sd
演示链接: Rextester
使用Replace
功能将字符Replace
为空值。
如下: -
select cast(replace(replace(replace(replace(replace(replace(replace
(replace(replace(replace(replace(replace(replace(replace(replace
(replace(replace(replace(replace(replace(replace(replace(replace
(replace(replace(replace(replace(replace(replace
(@str,'A',''),'B',''),'C',''),'D',''),'E',''),'F',''),'G',''),'H',''),'I',''),'J','')
,'K',''),'L',''),'M',''),'N',''),'O',''),'P',''),'Q',''),'R',''),'S',''),'T','')
,'U',''),'V',''),'W',''),'X',''),'Y',''),'Z',''),'$',''),',',''),' ','') as bigint)
注意:-
这个解决方案很丑陋而且性能很糟糕,但是我把它作为最后的解决方案发布了,希望能比其他解决方案更好。
如果你有25,000,000条记录,那么我建议最好对表格进行反Denormalize
。
添加标准bigint
列。
ALTER TABLE dbo.Data
ADD StrippedNumber AS BIGINT NULL
并使用数据UPDATE
列。
UPDATE dbo.Data SET StrippedNumber = CONVERT(BIGINT, dbo.fnFormatNumeric(AlphaNumeric))
此解决方案的唯一缺点是所有插入和更新必须使用AlphaNumeric
列中的数据手动更新StrippedNumber
列。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.