简体   繁体   English

提取字符串中的最后一个数字

[英]Extracting last number within string

I have the below sample data and I'm trying to extract the last number within the string.我有以下示例数据,我正在尝试提取字符串中的最后一个数字。 I have the following, which gets me part of the way there, but I'm not sure how to get the value where it isn't the last word.我有以下内容,这让我参与其中,但我不确定如何获得不是硬道理的价值。

right(TextDescription, patindex('%[^0-9]%',reverse(TextDescription)) - 1)

The result should be:结果应该是:

ID ID code代码
1 1个 10015662 10015662
2 2个 100040344 100040344
3 3个 10015370 10015370
4 4个 NULL NULL
5 5个 400337 400337

Sample data样本数据

Create Table #TestData
(
    ID int,
    TextDescription varchar(100)
)

insert into #TestData Values (1,'Data From JOE BLOGGS 10015662 tree 10015662')
insert into #TestData Values (2,'Fast Data From JOHN SMITH 10004034 MARY SMITH 100040344 plant')
insert into #TestData Values (3,'Data In 10015370 pot JONES')
insert into #TestData Values (4,'Fast Data From LEE tree')
insert into #TestData Values (5,'Direct Data 106600 JANE GREEN 400337')

If your interesting values are always found at the end, and are always preceeded by a non-digit, you can use the SUBSTRING with:如果您感兴趣的值总是在末尾找到,并且总是以非数字开头,则可以将SUBSTRING与:

  • lower boundary being the last non-digit before the last number location下边界是最后一个数字位置之前的最后一个非数字
  • length being the difference between last non-digit and first value of last number长度是最后一个非数字和最后一个数字的第一个值之间的差
WITH cte AS (
    SELECT ID, TextDescription,
           PATINDEX('%[0-9][^0-9]%', REVERSE(TextDescription) + ' ') AS first_space,
           PATINDEX('%[0-9]%'      , REVERSE(TextDescription)      ) AS last_digit 
    FROM #TestData
)  
SELECT ID, 
       SUBSTRING(TextDescription, 
                 LEN(TextDescription) -first_space +1,
                 first_space+1 -last_digit)              AS code
FROM cte

Check the demo here .此处查看演示。

Just another option using aa bit of JSON which will convert the string into an array and [key] will maintain the sequence.另一个选项使用 JSON 的一个位,它将字符串转换为数组,[key] 将保持序列。

Select A.ID 
      ,B.Value
 From  #TestData A
 Outer Apply (
                Select top 1 Value
                 From  OpenJSON( '["'+replace(string_escape(TextDescription,'json'),' ','","')+'"]' )
                 Where try_convert(int,Value) is not null
                 Order by [key] Desc
             ) B

Results结果

ID  Value
1   10015662
2   100040344
3   10015370
4   NULL
5   400337

The following will locate the last digit, trim the string at that point, find the preceding non-digit, and then perform another trim to get the final result.下面将找到最后一个数字,在该点修剪字符串,找到前面的非数字,然后再进行一次修剪以获得最终结果。 As in your original post, calculations are done on a reversed string to accommodate the lack of of a LASTPATINDEX() function. CROSS APPLY is used to build up intermediate results and to avoid duplication of subexpressions.与您的原始帖子一样,计算是在反向字符串上完成的,以适应LASTPATINDEX() function 的缺失。CROSS CROSS APPLY用于建立中间结果并避免子表达式重复。

select T.*, P1.Pos1, P2.Pos2, N.Result
from #TestData T
cross apply (select reverse(TextDescription) AS Reversed) R
cross apply (select nullif(patindex('%[0-9]%', R.Reversed), 0) AS Pos1) P1
cross apply (select stuff(R.Reversed, 1, P1.Pos1 - 1, '') AS Trim1) T1
cross apply (select patindex('%[^0-9]%', T1.Trim1 + 'X') AS Pos2) P2
cross apply (select reverse(left(T1.Trim1, P2.Pos2 - 1)) AS Result) N

-- Partly reduced
select T.*, reverse(left(T1.Trim1, patindex('%[^0-9]%', T1.Trim1 + 'X') - 1)) AS Result
from #TestData T
cross apply (select reverse(TextDescription) AS Reversed) R
cross apply (select stuff(R.Reversed, 1, nullif(patindex('%[0-9]%', R.Reversed), 0) - 1, '') AS Trim1) T1

This will handle a variety of forms, not just space-delimited values.这将处理各种 forms,而不仅仅是以空格分隔的值。

See this db<>fiddle .看到这个 db<>fiddle

Please try the following solution leveraging XML and XQuery.请尝试以下利用 XML 和 XQuery 的解决方案。

Notable points:值得注意的地方:

  • CROSS APPLY is tokenizing TextDescription column as XML. CROSS APPLY 将TextDescription列标记为 XML。
  • XQuery FLWOR expression is checking every token if it is castable as INTEGER data type. XQuery FLWOR 表达式正在检查每个标记是否可转换为 INTEGER 数据类型。 And filtering them out if they are not.如果不是,则过滤掉它们。
  • XPath predicate [last()] is giving us last INTEGER value. XPath 谓词[last()]给我们最后一个 INTEGER 值。

SQL SQL

-- DDL and sample data population, start
DECLARE @tbl Table (ID INT IDENTITY PRIMARY KEY, TextDescription varchar(100));
INSERT INTO @tbl (TextDescription) VALUES 
('Data From JOE BLOGGS 10015662 tree 10015662'),
('Fast Data From JOHN SMITH 10004034 MARY SMITH 100040344 plant'),
('Data In 10015370 pot JONES'),
('Fast Data From LEE tree'),
('Direct Data 106600 JANE GREEN 400337');
-- DDL and sample data population, end

DECLARE @separator CHAR(1) = SPACE(1);

SELECT t.*
    , c.query('for $x in /root/r[not(empty(xs:int(.)))]
        return $x
    ').value('(/r[last()]/text())[1]','INT') AS [code]
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' + 
      REPLACE(TextDescription, @separator, ']]></r><r><![CDATA[') + 
      ']]></r></root>' AS XML)) AS t1(c)
ORDER BY t.ID;

Output Output

ID ID TextDescription文字说明 code代码
1 1个 Data From JOE BLOGGS 10015662 tree 10015662数据来自 JOE BLOGGS 10015662 tree 10015662 10015662 10015662
2 2个 Fast Data From JOHN SMITH 10004034 MARY SMITH 100040344 plant快速数据来自 JOHN SMITH 10004034 MARY SMITH 100040344 工厂 100040344 100040344
3 3个 Data In 10015370 pot JONES数据 In 10015370 pot JONES 10015370 10015370
4 4个 Fast Data From LEE tree来自 LEE 树的快速数据 NULL NULL
5 5个 Direct Data 106600 JANE GREEN 400337直接数据 106600 JANE GREEN 400337 400337 400337
CREATE FUNCTION [ExtractInteger](@String VARCHAR(2000))
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE @Count INT
DECLARE @IntNumbers VARCHAR(1000)
SET @Count = 0
SET @IntNumbers = ''

WHILE @Count <= LEN(@String)
BEGIN

IF SUBSTRING(@String,@Count,1) = ' '
BEGIN
SET @IntNumbers = @IntNumbers + ' ' 
END

IF SUBSTRING(@String,@Count,1) >= '0'
AND SUBSTRING(@String,@Count,1) <= '9'
BEGIN
SET @IntNumbers = @IntNumbers + SUBSTRING(@String,@Count,1)
END
SET @Count = @Count + 1
END

RETURN LTRIM(RTRIM(@IntNumbers))
END

The ExtractInteger function will fetch only numbers and spaces, and the below select will take the last word as number: ExtractInteger function 将仅提取数字和空格,下面的 select 将最后一个单词作为数字:

select right(dbo.ExtractInteger('My 3rd Phone Number is 323-111-CALL'), charindex(' ', reverse(dbo.ExtractInteger('My 3rd Phone Number is 323-111-CALL')) + ' ') - 1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM