根据特定子字符串短语从中获取数字值

6
我有以下的字母和数字混合文本。
 ID Textfield
 1  estimated left ventricular ejection fraction 60-65%
 2  estimated left ventricular ejection fraction is 55-60%
 3  Left ventricular ejection fraction is approximately 40 to 50%
 4  Fractional Short 50 %( 28-48) LV mass 83 gm (<220) systolic function  left ventricular ejection fraction = 52 % 

我需要提取左室射血分数的数字值。

输出应为:

ID Lowerbound   Upperbound
1   60            65
2   55            60
3   40            50
4   52            NULL 

我尝试了下面的SQL语法来查询字符 - 对于ID 3和4它没有成功(对于ID 4,它给出了50,但应该是52)。

SELECT SUBSTRING(textfield,CHARINDEX('-', 
textfield)-1,10),dbo.udf_GetNumeric(RIGHT(left(textfield,CHARINDEX('- 
',textfield)-1 ),10))AS Lower_bound,left(textfield, CHARINDEX('-', 
textfield) )


,dbo.udf_GetNumeric(SUBSTRING(textfield,CHARINDEX('-', textfield)+1,5)) 
    AS Upper_bound

提前感谢你


您在文本框中输入的是自由格式文本,我相信简单的逻辑无法提取您想要的数字。我会采取的方法是,在创建数据(插入)的人员进行该过程时,我会制定一些规则,以确保可以正确提取数字。 - Surendra
很抱歉要说这个。但实际问题出在数据结构上。你应该创建额外的字段来保存相关的数字数据。如果你真的必须使用一个字段来保存所有这样的数据,那么请遵循任何文本格式,比如 CSVXML 或者适合你的任何格式,但不要提出这样一种松散的数据结构。你也可以创建自己的小标准,比如 Frac='%';LFrac='60';HFrac='65' - Hamees A. Khan
1
这是一个不太适合使用SQL的用例。你不能使用像Python这样的工具来处理文本吗? - Gordon Linoff
我的方法是逐行进行处理,在单词“左心室射血分数”后逐个解析字符,以查看它们是否为数字,然后相应地处理它们。虽然有点混乱,但对于这种情况应该可以工作。正如@GordonLinoff在上面提到的,这绝对是SQL的一个相当糟糕的用例。 - Daniel Marcus
@GordonLinoff 我没有文本字段的控制权。我同意这是一个糟糕的用例,但我正在根据要求寻找解决方案。 - user3594484
显示剩余2条评论
3个回答

1
这将使用几个来逐渐靠近。一些替换使字符串可比较,从末尾开始的第一个空格是边界。其余部分相对容易理解。
DECLARE @tbl TABLE(ID INT, Textfield VARCHAR(500));
INSERT INTO @tbl VALUES
 (1,'estimated left ventricular ejection fraction 60-65%')
,(2,'estimated left ventricular ejection fraction is 55-60%')
,(3,'Left ventricular ejection fraction is approximately 40 to 50%')
,(4,'Fractional Short 50 %( 28-48) LV mass 83 gm (<220) systolic function  left ventricular ejection fraction = 52 % ');

SELECT ID
      ,Rev
      ,substr
      ,CASE WHEN hyph>0 THEN LEFT(substr,hyph-1) ELSE substr END AS LowerBound
      ,CASE WHEN hyph>0 THEN SUBSTRING(substr,hyph+1,10) ELSE NULL END AS UpperBound
FROM @tbl t
CROSS APPLY(SELECT REVERSE(RTRIM(REPLACE(REPLACE(t.Textfield,' to ','-'),' %','%')))) AS A(Rev)
CROSS APPLY(SELECT PATINDEX('% [^1-9]%',A.Rev)) AS B(pos)
CROSS APPLY(SELECT LTRIM(RTRIM(REPLACE(REVERSE(LEFT(A.Rev,B.pos)),'%','')))) AS C(substr)
CROSS APPLY(SELECT CHARINDEX('-',C.substr)) AS D(hyph);

0

从技术上讲,这将解决您的 Upperbound 问题,至少在您的示例数据范围内:

CASE WHEN RIGHT(TextField, 4) LIKE '%-[1234567890]' + '%' 
    THEN Left(Right(TextField,3),2) 
WHEN RIGHT(TextField, 6) LIKE '%to [1234567890]%'
    THEN Left(Right(TextField,3),2) 
WHEN RIGHT(TextField, 6) LIKE '%= [1234567890]%'
    THEN Left(Right(TextField,4),2) 
END AS UpperBound

但是,你的示例数据真的很糟糕。


4
了解,您可以使用“%[0-9]%”代替逐个书写数字。 - Daniel Marcus

0

请尝试使用此代码,并让我知道是否适用于您的全部数据集。这里的假设是:

1)数字总是在词组“左室射血分数”之后出现

2)在词组“左室射血分数”之后,除了定义下限和上限值的其他数字之外,没有其他数字

3)下限和上限始终从左到右排列(由小到大)

4)您起始表的名称是#temp

 declare @temp table (id int, field varchar(max))
 insert @temp

 select id, replace(right(Textfield, len(Textfield)-charindex('left ventricular ejection fraction', Textfield)+1),
'left ventricular ejection fraction','') field  
 from #temp 

 declare @holding table (id int, lowerbd varchar(max), upperbd varchar(max)) 
 declare @iterator int =1
 declare @prevfield varchar(max)
 declare @field varchar(max)
 declare @originalfield varchar(max)
 declare @number varchar(max)=''

 while @iterator<=(select max(id) from @temp)
 begin

 select @originalfield = field from @temp where id=@iterator

 while len(@originalfield) >0
 begin

 set @prevfield=@field

 select @field=left(@originalfield,1) 

 set @originalfield= 
 case 
 when len(@originalfield)>1 then substring(@originalfield, 2, len(@originalfield))
 else '' end 

 if  @field like '%[0-9]%'  
 begin
 set @number = @number+@field
 end
 if @field like '%[0-9]%' and @prevfield like '%[0-9]%'
 begin
     if not exists(select 1 from @holding where id= @iterator)
     begin
     insert @holding
     select @iterator, @number, null
     set @number=''
     end
     else   
     begin
     insert @holding
     select @iterator, null, @number
     set @number=''
     end

 end


end
set @iterator=@iterator+1
end

select id, max(lowerbd)lowerbd, max(upperbd)upperbd from @holding 
group by id

我认为这里不需要循环(甚至嵌套循环更糟)。这是过程式思维...也许有些情况下这种方法是适当的,但在这些情况下,我会说T-SQL是错误的工具。 - Shnugo
那么你会如何建议使用 T-SQL 来解决这个问题呢?OP 要求在此处使用 SQL Server,不能使用任何其他工具。 - Daniel Marcus
你上面的解决方案只适用于那4个示例行。我认为想法是提出一个解决方案,无论在“左心室射血分数”一词后提供什么文本,都能够起作用。 - Daniel Marcus
只需剪掉此片段之前的所有内容?我的解决方案查看字符串的结尾,而不查看之前的部分。 - Shnugo
你为什么认为这个特定的文本如此重要? - Shnugo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接