MySQL 5.5-如何从具有重复字符串的字段中提取文本的一部分?

时间:2019-01-17 17:03:48

标签: mysql

我有这样的字段:

for (int b : a) {

,我正在尝试从左侧的第一个p = p + b; 之后提取文本。这将是一个或两个数字/字母。另外,同时我想先从左边看UPDATE</transactionType><column><name>prio</name><newValue>5</newValue><oldValue>1</oldValue><newValue>aaa<oldValue>10863321</oldValue></column></row></table></businessObjectChanges> UPDATE</transactionType><column><name>prio</name><newValue>51</newValue><oldValue>11</oldValue><newValue>bbb<oldValue>10863321</oldValue></column></row></table></businessObjectChanges> 。结果是:

<newValue>

4 个答案:

答案 0 :(得分:1)

由于它是不完整的XML,因此我们使用简单的字符串函数。

LOCATE可以找到子字符串的位置。

LEFT从头到位置获取一个子字符串。

从该子字符串中,SUBSTRING_INDEX函数很容易在最终标签之后获取字符。

示例代码:

-- test table
drop table if exists YourTable;
create table YourTable (col varchar(1000));

-- Sample data
insert into YourTable (col) values
('UPDATE</transactionType><column><name>prio</name><newValue>5</newValue><oldValue>1</oldValue><newValue>aaa<oldValue>10863321</oldValue></column></row></table></businessObjectChanges>'),
('UPDATE</transactionType><column> <name>prio</name><newValue>51</newValue><oldValue>11</oldValue><newValue>bbb<oldValue>10863321</oldValue></column></row></table></businessObjectChanges>');

-- Query
SELECT 
 SUBSTRING_INDEX(LEFT(col, LOCATE('</oldValue>', col)-1),'>',-1) AS oldValue,
 SUBSTRING_INDEX(LEFT(col, LOCATE('</newValue>', col)-1),'>',-1) AS newValue
FROM YourTable;

结果:

oldValue    newValue
1           5
11          51

妊娠here

的测试

旁注:

在MySql 8中,您也可以为此使用REGEXP_SUBSTR

SELECT  
REGEXP_SUBSTR(col,'(?<=<oldValue>)[^<>]*(?=</oldValue)',1,1) as oldValue,
REGEXP_SUBSTR(col,'(?<=<newValue>)[^<>]*(?=</newValue>)',1,1) as newValue
FROM YourTable;

db <>小提琴here

的测试

(但请保持沉默。有些人会因为使用正则表达式来解析XML而对您不满意。例如here
但是再说一次,无效的XML实际上不是XML)

答案 1 :(得分:0)

正如我所理解的那样,您仅粘贴了xml字段的一部分。如果它是有效的xml,则可以通过函数ExtractValue

使用xpath表达式

我将为您提供一个简单的示例:

数据定义

create table Test(id integer, title varchar(2000));
insert into Test(id, title) values(1, "<a><b>X</b><b>Y</b></a>");

查询

select ExtractValue(title, '/a/b[1]') from Test;

此查询返回标签a内的第一个元素b(请注意查询中的“ 1”。在这种情况下,结果为X

因此,在您的情况下,您可以在单个查询中使用两个ExtractValue函数来选择第一个newValue标记和第一个oldValue标记。

链接:ExtractValue function in MySQL Documentation

答案 2 :(得分:0)

由于它不是正确的XML,让我们尝试一些底层字符串工具。

mysql> SELECT SUBSTRING_INDEX(
                  SUBSTRING_INDEX(
'UPDATE</transactionType><column><name>prio</name><newValue>51</newValue><oldValue>11</oldValue><newValue>bbb<oldValue>10863321</oldValue></column></row></table></businessObjectChanges>',
                                  '</newValue>', 1),
                              '<newValue>', -1) AS x;
+----+
| x  |
+----+
| 51 |
+----+
1 row in set (0.00 sec)

说明:

  • 内部SUBSTRING_INDEX通过第一个</newValue>获取子字符串。
  • 外部SUBSTRING_INDEX在第一个<newValue>之后获取文本

尝试其他字符串。

这对于至少十年前的任何MySQL版本都适用。

<oldvalue>应该以相同的方式工作,并且可以成为SELECT中的第二个“列”。

答案 3 :(得分:0)

SUBSTRING_INDEX函数在某些情况下很有用。对于包含指定标签的“格式正确”的值,我们可以获得可用的结果。但是当值的格式不正确时,这种方法就会瓦解(返回潜在的意外结果)。

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(  t.foo  ,'</oldValue>',1),'<oldValue>',-1) AS first_oldValue
     , SUBSTRING_INDEX(SUBSTRING_INDEX(  t.foo  ,'</newValue>',1),'<newValue>',-1) AS first_newValue
  FROM ( SELECT 'UPDATE</transactionType><column><name>prio</name><newValue>5</newValue><oldValue>1</oldValue><newValue>aaa<oldValue>10863321</oldValue></column></row></table></businessObjectChanges>' AS foo 
         UNION ALL 
         SELECT 'UPDATE</transactionType><column><name>prio</name><newValue>51</newValue><oldValue>11</oldValue><newValue>bbb<oldValue>10863321</oldValue></column></row></table></businessObjectChanges>'
       ) t
 WHERE t.foo LIKE '%<oldValue>%</oldValue>%'
   AND t.foo LIKE '%<newValue>%</newValue>%'

我们可以将完整性检查合并到SELECT列表中的表达式中

SELECT CASE WHEN t.foo LIKE '%<oldValue>%</oldValue>%' THEN 
         SUBSTRING_INDEX(SUBSTRING_INDEX( t.foo ,'</oldValue>',1),'<oldValue>',-1)
       END AS first_oldValue
     , CASE WHEN t.foo LIKE '%<newValue>%</newValue>%' THEN
         SUBSTRING_INDEX(SUBSTRING_INDEX( t.foo ,'</newValue>',1),'<newValue>',-1) 
       END AS first_newValue
  FROM ( SELECT 'UPDATE</transactionType><column><name>prio</name><newValue>5</newValue><oldValue>1</oldValue><newValue>aaa<oldValue>10863321</oldValue></column></row></table></businessObjectChanges>' AS foo 
         UNION ALL 
         SELECT 'UPDATE</transactionType><column><name>prio</name><newValue>51</newValue><oldValue>11</oldValue><newValue>bbb<oldValue>10863321</oldValue></column></row></table></businessObjectChanges>'
       ) t