假设我有这样的数据:
string 1: 003Preliminary Examination Plan
string 2: Coordination005
string 3: Balance1000sheet
我期望的输出是
string 1: 003
string 2: 005
string 3: 1000
我想在sql中实现它。 请帮忙。 在此先感谢:)
答案 0 :(得分:85)
首先创建 UDF
CREATE FUNCTION dbo.udf_GetNumeric
(@strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
DECLARE @intAlpha INT
SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric)
BEGIN
WHILE @intAlpha > 0
BEGIN
SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric )
END
END
RETURN ISNULL(@strAlphaNumeric,0)
END
GO
现在使用 function
作为
SELECT dbo.udf_GetNumeric(column_name)
from table_name
<强> SQL FIDDLE 强>
我希望这能解决你的问题。
<强> Reference 强>
答案 1 :(得分:30)
试试这个 -
<强>查询:强>
DECLARE @temp TABLE
(
string NVARCHAR(50)
)
INSERT INTO @temp (string)
VALUES
('003Preliminary Examination Plan'),
('Coordination005'),
('Balance1000sheet')
SELECT LEFT(subsrt, PATINDEX('%[^0-9]%', subsrt + 't') - 1)
FROM (
SELECT subsrt = SUBSTRING(string, pos, LEN(string))
FROM (
SELECT string, pos = PATINDEX('%[0-9]%', string)
FROM @temp
) d
) t
<强>输出:强>
----------
003
005
1000
答案 2 :(得分:10)
查询:
DECLARE @temp TABLE
(
string NVARCHAR(50)
)
INSERT INTO @temp (string)
VALUES
('003Preliminary Examination Plan'),
('Coordination005'),
('Balance1000sheet')
SELECT SUBSTRING(string, PATINDEX('%[0-9]%', string), PATINDEX('%[0-9][^0-9]%', string + 't') - PATINDEX('%[0-9]%',
string) + 1) AS Number
FROM @temp
答案 3 :(得分:8)
请尝试:
declare @var nvarchar(max)='Balance1000sheet'
SELECT LEFT(Val,PATINDEX('%[^0-9]%', Val+'a')-1) from(
SELECT SUBSTRING(@var, PATINDEX('%[0-9]%', @var), LEN(@var)) Val
)x
答案 4 :(得分:3)
通过之前的查询,我得到了以下结果:
'AAAA1234BBBB3333'&gt;&gt;&gt;&gt;输出:1234
' - çã+ 0!\aº1234'&gt;&gt;&gt;&gt;输出:0
以下代码返回所有数字字符:
第一输出:12343333
第二次输出:01234
declare @StringAlphaNum varchar(255)
declare @Character varchar
declare @SizeStringAlfaNumerica int
declare @CountCharacter int
set @StringAlphaNum = 'AAAA1234BBBB3333'
set @SizeStringAlfaNumerica = len(@StringAlphaNum)
set @CountCharacter = 1
while isnumeric(@StringAlphaNum) = 0
begin
while @CountCharacter < @SizeStringAlfaNumerica
begin
if substring(@StringAlphaNum,@CountCharacter,1) not like '[0-9]%'
begin
set @Character = substring(@StringAlphaNum,@CountCharacter,1)
set @StringAlphaNum = replace(@StringAlphaNum, @Character, '')
end
set @CountCharacter = @CountCharacter + 1
end
set @CountCharacter = 0
end
select @StringAlphaNum
答案 5 :(得分:1)
我发现这种方法比最高投票的答案快 3 倍。创建以下函数 dbo.GetNumbers:
CREATE FUNCTION dbo.GetNumbers(@String VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN;
WITH
Numbers
AS (
--Step 1.
--Get a column of numbers to represent
--every character position in the @String.
SELECT 1 AS Number
UNION ALL
SELECT Number + 1
FROM Numbers
WHERE Number < LEN(@String)
)
,Characters
AS (
SELECT Character
FROM Numbers
CROSS APPLY (
--Step 2.
--Use the column of numbers generated above
--to tell substring which character to extract.
SELECT SUBSTRING(@String, Number, 1) AS Character
) AS c
)
--Step 3.
--Pattern match to return only numbers from the CTE
--and use STRING_AGG to rebuild it into a single string.
SELECT @String = STRING_AGG(Character,'')
FROM Characters
WHERE Character LIKE '[0-9]'
--allows going past the default maximum of 100 loops in the CTE
OPTION (MAXRECURSION 8000)
RETURN @String
END
GO
测试
测试目的:
SELECT dbo.GetNumbers(InputString) AS Numbers
FROM ( VALUES
('003Preliminary Examination Plan') --output: 003
,('Coordination005') --output: 005
,('Balance1000sheet') --output: 1000
,('(111) 222-3333') --output: 1112223333
,('1.38hello@f00.b4r#\-6') --output: 1380046
) testData(InputString)
性能测试: 开始设置测试数据...
--Add table to hold test data
CREATE TABLE dbo.NumTest (String VARCHAR(8000))
--Make an 8000 character string with mix of numbers and letters
DECLARE @Num VARCHAR(8000) = REPLICATE('12tf56se',800)
--Add this to the test table 500 times
DECLARE @n INT = 0
WHILE @n < 500
BEGIN
INSERT INTO dbo.NumTest VALUES (@Num)
SET @n = @n +1
END
现在测试 dbo.GetNumbers 函数:
SELECT dbo.GetNumbers(NumTest.String) AS Numbers
FROM dbo.NumTest -- Time to complete: 1 min 7s
然后在相同的数据上测试来自 top voted answer 的 UDF。
SELECT dbo.udf_GetNumeric(NumTest.String)
FROM dbo.NumTest -- Time to complete: 3 mins 12s
Inspiration for dbo.GetNumbers
小数
如果你需要它来处理小数,你可以使用以下任何一种方法,我发现它们之间没有明显的性能差异。
'[0-9]'
更改为 '[0-9.]'
Character LIKE '[0-9]'
更改为 ISNUMERIC(Character) = 1
(SQL 将单个小数视为数字)奖金
通过使用以下选项替换 WHERE Character LIKE '[0-9]'
,您可以轻松地使其适应不同的要求:
WHERE Letter LIKE '[a-zA-Z]' --Get only letters
WHERE Letter LIKE '[0-9a-zA-Z]' --Remove non-alphanumeric
WHERE Letter LIKE '[^0-9a-zA-Z]' --Get only non-alphanumeric
答案 6 :(得分:1)
首先找出数字的起始长度,然后反转字符串以再次找出第一个位置(这将为您提供数字的结束位置)。现在,如果您从两个数字中减去 1 并从字符串全长中减去它,您将只得到数字长度。现在使用 SUBSTRING
获取号码declare @fieldName nvarchar(100)='AAAA1221.121BBBB'
declare @lenSt int=(select PATINDEX('%[0-9]%', @fieldName)-1)
declare @lenEnd int=(select PATINDEX('%[0-9]%', REVERSE(@fieldName))-1)
select SUBSTRING(@fieldName, PATINDEX('%[0-9]%', @fieldName), (LEN(@fieldName) - @lenSt -@lenEnd))
答案 7 :(得分:1)
此UDF适用于所有类型的字符串:
CREATE FUNCTION udf_getNumbersFromString (@string varchar(max))
RETURNS varchar(max)
AS
BEGIN
WHILE @String like '%[^0-9]%'
SET @String = REPLACE(@String, SUBSTRING(@String, PATINDEX('%[^0-9]%', @String), 1), '')
RETURN @String
END
答案 8 :(得分:1)
declare @puvodni nvarchar(20)
set @puvodni = N'abc1d8e8ttr987avc'
WHILE PATINDEX('%[^0-9]%', @puvodni) > 0 SET @puvodni = REPLACE(@puvodni, SUBSTRING(@puvodni, PATINDEX('%[^0-9]%', @puvodni), 1), '' )
SELECT @puvodni
答案 9 :(得分:0)
我没有创建函数的权限,但拥有类似
的文字["blahblah012345679"]
并且需要从中间提取数字
请注意,这是假设数字是组合在一起的,而不是字符串的开头和结尾。
select substring(column_name,patindex('%[0-9]%', column_name),patindex('%[0-9][^0-9]%', column_name)-patindex('%[0-9]%', column_name)+1)
from table name
答案 10 :(得分:0)
只需对@Epsicron的答案进行一些修改
.mat-form-field-label {
white-space: pre-wrap;
}
不需要临时变量
答案 11 :(得分:0)
尽管这是一个古老的线程,它是google搜索中的第一个线程,但我想出了一个不同于以前的答案。这将使您可以通过准则来决定字符串中要保留的内容,无论该准则可能是什么。如果需要,可以将其放在函数中以反复调用。
declare @String VARCHAR(MAX) = '-123. a 456-78(90)'
declare @MatchExpression VARCHAR(255) = '%[0-9]%'
declare @return varchar(max)
WHILE PatIndex(@MatchExpression, @String) > 0
begin
set @return = CONCAT(@return, SUBSTRING(@string,patindex(@matchexpression, @string),1))
SET @String = Stuff(@String, PatIndex(@MatchExpression, @String), 1, '')
end
select (@return)
答案 12 :(得分:0)
在Oracle中
您可以使用以下方法获得想要的东西:
SUBSTR('ABCD1234EFGH',REGEXP_INSTR ('ABCD1234EFGH', '[[:digit:]]'),REGEXP_COUNT ('ABCD1234EFGH', '[[:digit:]]'))
示例查询:
SELECT SUBSTR('003Preliminary Examination Plan ',REGEXP_INSTR ('003Preliminary Examination Plan ', '[[:digit:]]'),REGEXP_COUNT ('003Preliminary Examination Plan ', '[[:digit:]]')) SAMPLE1,
SUBSTR('Coordination005',REGEXP_INSTR ('Coordination005', '[[:digit:]]'),REGEXP_COUNT ('Coordination005', '[[:digit:]]')) SAMPLE2,
SUBSTR('Balance1000sheet',REGEXP_INSTR ('Balance1000sheet', '[[:digit:]]'),REGEXP_COUNT ('Balance1000sheet', '[[:digit:]]')) SAMPLE3 FROM DUAL
答案 13 :(得分:0)
考虑到其他答案,我想出了自己的答案: 试试这个:
SUBSTRING('your-string-here', PATINDEX('%[0-9]%', 'your-string-here'), LEN('your-string-here'))
NB:仅适用于字符串中的第一个int,例如:abc123vfg34返回123。
答案 14 :(得分:0)
SELECT regexp_replace(column_name,'[^ 0-9] *','','g');
答案 15 :(得分:0)
T-SQL函数从文本读取所有整数,并使用起始搜索项(可选)从左或右返回指定索引处的整数:
create or alter function dbo.udf_number_from_text(
@text nvarchar(max),
@search_term nvarchar(1000) = N'',
@number_position tinyint = 1,
@rtl bit = 0
) returns int
as
begin
declare @result int = 0;
declare @search_term_index int = 0;
if @text is null or len(@text) = 0 goto exit_label;
set @text = trim(@text);
if len(@text) = len(@search_term) goto exit_label;
if len(@search_term) > 0
begin
set @search_term_index = charindex(@search_term, @text);
if @search_term_index = 0 goto exit_label;
end;
if @search_term_index > 0
if @rtl = 0
set @text = trim(right(@text, len(@text) - @search_term_index - len(@search_term) + 1));
else
set @text = trim(left(@text, @search_term_index - 1));
if len(@text) = 0 goto exit_label;
declare @patt_number nvarchar(10) = '%[0-9]%';
declare @patt_not_number nvarchar(10) = '%[^0-9]%';
declare @number_start int = 1;
declare @number_end int;
declare @found_numbers table (id int identity(1,1), val int);
while @number_start > 0
begin
set @number_start = patindex(@patt_number, @text);
if @number_start > 0
begin
if @number_start = len(@text)
begin
insert into @found_numbers(val)
select cast(substring(@text, @number_start, 1) as int);
break;
end;
else
begin
set @text = right(@text, len(@text) - @number_start + 1);
set @number_end = patindex(@patt_not_number, @text);
if @number_end = 0
begin
insert into @found_numbers(val)
select cast(@text as int);
break;
end;
else
begin
insert into @found_numbers(val)
select cast(left(@text, @number_end - 1) as int);
if @number_end = len(@text)
break;
else
begin
set @text = trim(right(@text, len(@text) - @number_end));
if len(@text) = 0 break;
end;
end;
end;
end;
end;
if @rtl = 0
select @result = coalesce(a.val, 0)
from (select row_number() over (order by m.id asc) as c_row, m.val
from @found_numbers as m) as a
where a.c_row = @number_position;
else
select @result = coalesce(a.val, 0)
from (select row_number() over (order by m.id desc) as c_row, m.val
from @found_numbers as m) as a
where a.c_row = @number_position;
exit_label:
return @result;
end;
示例:
select dbo.udf_number_from text(N'Text text 10 text, 25 term', N'term',2,1);
返回10;
答案 16 :(得分:0)
为了它的地狱...
此解决方案与所有早期解决方案不同,即:
但是首先-请注意,问题未指定此类字符串的存储位置。在下面的解决方案中,我创建了CTE,将其作为将这些字符串放入某种“源表”中的快速而肮脏的方式。
还请注意-此解决方案使用recursive common table expression(CTE)-因此,请不要对此处使用两个CTE感到困惑。第一个只是使数据适用于解决方案-但是,仅第二个CTE才可解决此问题。您可以修改代码以使第二个CTE查询您现有的表,视图等。
最后-我的编码很冗长,尝试使用列和CTE名称来解释发生了什么,您也许可以稍微简化一下此解决方案。我添加了一些伪电话号码,其中一些格式(预期的和非典型的,视情况而定)很有趣。
with SOURCE_TABLE as (
select '003Preliminary Examination Plan' as numberString
union all select 'Coordination005' as numberString
union all select 'Balance1000sheet' as numberString
union all select '1300 456 678' as numberString
union all select '(012) 995 8322 ' as numberString
union all select '073263 6122,' as numberString
),
FIRST_CHAR_PROCESSED as (
select
len(numberString) as currentStringLength,
isNull(cast(try_cast(replace(left(numberString, 1),' ','z') as tinyint) as nvarchar),'') as firstCharAsNumeric,
cast(isNull(cast(try_cast(nullIf(left(numberString, 1),'') as tinyint) as nvarchar),'') as nvarchar(4000)) as newString,
cast(substring(numberString,2,len(numberString)) as nvarchar) as remainingString
from SOURCE_TABLE
union all
select
len(remainingString) as currentStringLength,
cast(try_cast(replace(left(remainingString, 1),' ','z') as tinyint) as nvarchar) as firstCharAsNumeric,
cast(isNull(newString,'') as nvarchar(3999)) + isNull(cast(try_cast(nullIf(left(remainingString, 1),'') as tinyint) as nvarchar(1)),'') as newString,
substring(remainingString,2,len(remainingString)) as remainingString
from FIRST_CHAR_PROCESSED fcp2
where fcp2.currentStringLength > 1
)
select
newString
,* -- comment this out when required
from FIRST_CHAR_PROCESSED
where currentStringLength = 1
那么这是怎么回事?
基本上,在CTE中,我们选择第一个字符,并使用try_cast
(see docs)将其转换为tinyint
(这是一个足够大的数据类型,可以容纳一位数字)数字)。请注意,SQL Server中的类型转换规则说空字符串(或空格)将解析为零,因此添加了nullif
来强制空格和空字符串解析为null({ {3}})(否则,只要在源数据中遇到空格,我们的结果将包括一个零字符)。
CTE还返回第一个字符之后的所有内容-这成为我们对CTE进行递归调用的输入;换句话说:现在让我们处理下一个字符。
最后,通过串联生成了CTE中的字段newString
(在第二个SELECT
中)。对于任何给定的列,在两个SELECT
语句之间使用递归CTE see discussion-包括列大小。因为我们知道我们最多添加一个字符,所以我们将该字符转换为nvarchar(1),并将newString
(到目前为止)转换为nvarchar(3999)。串联后,结果将为nvarchar(4000)-与我们在第一个SELECT
中执行的类型转换匹配。
如果运行此查询并排除WHERE
子句,您将了解发生了什么-但是行的顺序可能很奇怪。 (您不一定会看到与单个输入值有关的所有行都分组在一起,但您仍然应该能够看到)。
希望这是一个有趣的选项,可能会帮助一些想要严格基于表达式的解决方案的人。
答案 17 :(得分:-2)
如果您使用的是Postgres,并且有类似“ 2000-一些示例文本”的数据,请尝试使用子字符串和位置组合,否则,如果在您的方案中没有定界符,则需要编写正则表达式:
SUBSTRING(Column_name from 0 for POSITION('-' in column_name) - 1) as
number_column_name
答案 18 :(得分:-3)
在查询中,您可以替换任何字符,它不是数字,没有任何内容:
REPLACE( ISNULL( column_name, '' ), '[^0-9]', '' )