我有这样的数据:

string 1: 003Preliminary Examination Plan   
string 2: Coordination005  
string 3: Balance1000sheet


我期望的输出是

string 1: 003
string 2: 005
string 3: 1000


我想实现它在SQL中。

评论

所以您要进行选择并从“:”之后的值中提取数字?

#1 楼

首先创建此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

希望这可以解决您的问题。

参考

评论


尽管它可以从字符串中提取并连接所有数字,但是这样可以解决问题,例如/p-1544937/apartment-flat-6th-october.html将返回15449376,这并不总是您所需要的

– System24 Tech
2014年7月3日在14:03

这是源blog.sqlauthority.com/2008/10/14/…

– Pரதீப்
2015年11月26日15:36

它不处理十进制数字。例如,输入“ 10.95”将返回“ 1095”

–造口术
18年1月2日,18:18



它实际上应该返回一个INT。返回CAST(ISNULL(@strAlphaNumeric,0)AS INT)

–造口术
18年1月2日在18:19

在给定全数字255个字符的字符串的情况下,@ stomy会冒出一个很好的溢出错误(实际上比这还少)。

–马修·金登(Mathieu Guindon)
18年7月5日在19:22

#2 楼

试试这个-

查询:

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


评论


虽然这个答案给我留下了深刻的印象,它很好地解决了OP的问题,但应注意,该解决方案仅适用于连续的数字序列。对于像Coor60nation005这样的字符串,它将返回60而不是结尾005

–保达
2015年8月17日15:49



对该答案和Baodad的评论+1,因为这恰好是我正在寻找的行为,但不是我接受的答案。

–马特
18-11-27在13:21

它不适用于(111)222-3333。我想要1112223333

–金狮
12月22日下午16:56

#3 楼

查询:

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


评论


这不适用于空格或分隔的数字,但可以回答问题。

– ViniciusGonçalves
18-2-19在18:17



什么是“字符串+'t'”?

–Vnge
1月21日22:09

#4 楼

请尝试:

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


评论


声明@var nvarchar(max)='Balance1000sheet123'SELECT LEFT(Val,PATINDEX('%[^ 0-9]%',Val +'a')-1)from(SELECT SUBSTRING(@var,PATINDEX('%[ 0-9]%',@ var),LEN(@var))Val)x。数值不是连续的。

–普拉哈拉德·加加尔(Prahalad Gaggar)
13年5月21日在10:15

它将给出字符串中的第一个数字。即1000

– TechDo
13年5月21日在10:17

是的,情况可能也是Balance1000sheet123

–阿维纳什·梅塔(Avinash Mehta)
13年5月21日在10:19

#5 楼

通过先前的查询,我得到以下结果:

'AAAA1234BBBB3333'>>>>输出:1234

'-çã+ 0!\aº1234'>>>>输出: 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


评论


当心:迭代每个字符的解决方案在T-SQL中的性能通常很差。一旦我用内置的REPLACE()函数替换了执行简单替换的类似循环,性能便提高了5000%(处理速度提高了50倍)。换句话说,这会使查询慢50倍。使用内置的文本处理功能避免循环。在最坏的情况下,请在.NET中创建自定义文本处理功能,并将其链接到SQL Server。

– Miroxlav
16年2月18日在8:59

努诺,这不太有效。在WHILE循环中,测试字符是否为数字,如果不是,则缩短字符串;否则,请缩短字符串。但是,您忽略了更新@SizeStringAlfaNumerica。否则,谢谢! :)不过,我会让您更新代码。

– jp2code
17年2月14日在15:01

#6 楼

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


#7 楼

我没有创建函数的权限,但有

["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


#8 楼

只需对@Epsicron的答案进行一些修改

SELECT SUBSTRING(string, PATINDEX('%[0-9]%', string), PATINDEX('%[0-9][^0-9]%', string + 't') - PATINDEX('%[0-9]%', 
                    string) + 1) AS Number
FROM (values ('003Preliminary Examination Plan'),
    ('Coordination005'),
    ('Balance1000sheet')) as a(string)


不需要临时变量

#9 楼

尽管这是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)


#10 楼

此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


#11 楼

考虑到其他答案,我想出了自己的答案:
尝试一下:

SUBSTRING('your-string-here', PATINDEX('%[0-9]%', 'your-string-here'), LEN('your-string-here'))


NB:仅适用于字符串中的第一个int,例如:abc123vfg34返回123。

#12 楼

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;

#13 楼

麻烦的是...
此解决方案与所有早期解决方案不同,即:

无需创建函数
无需使用模式匹配
不需要临时表
此解决方案使用递归公用表表达式(CTE)

但是首先-请注意,问题未指定此类字符串的存储位置。在下面的解决方案中,我创建了CTE,将其作为将这些字符串放入某种“源表”中的快捷方法。
请注意-此解决方案使用递归公用表表达式(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(请参阅文档)将其转换为tinyint(对于单个数字而言,该数据类型足够大)。请注意,SQL Server中的类型转换规则说空字符串(或空格)将解析为零,因此添加了nullif来强制空格和空字符串解析为null(请参见讨论)(否则每当源数据中遇到空格时,我们的结果将包含一个零字符。)
CTE还会在第一个字符之后返回所有内容-这成为我们对CTE进行递归调用的输入;换句话说:现在让我们处理下一个字符。
最后,通过串联生成CTE中的字段newString(在第二个SELECT中)。对于递归CTE,任何给定列(包括列大小)的两个SELECT语句之间的数据类型必须匹配。因为我们知道我们最多添加一个字符,所以我们将该字符转换为nvarchar(1),并将newString(到目前为止)转换为nvarchar(3999)。串联后,结果将为nvarchar(4000)-与我们在第一个SELECT中执行的类型转换匹配。
如果运行此查询并排除WHERE子句,您将了解正在发生的事情-但是这些行的顺序可能很奇怪。 (您不一定会看到与单个输入值相关的所有行都被分组在一起-但您仍然应该能够遵循)。
希望这是一个有趣的选择,它可能会帮助一些想要严格基于表达式的解决方案的人。

#14 楼

在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


#15 楼

如果您使用的是Postgres,并且有类似“ 2000-一些示例文本”的数据,请尝试使用子字符串和位置组合,否则,如果在您的情况中没有定界符,则需要编写正则表达式:

SUBSTRING(Column_name from 0 for POSITION('-' in column_name) - 1) as 
number_column_name