我需要对mysql数据库中的字段执行相当于sed
的操作,字段数据的格式为xml。
从本质上讲,我需要在下面找到{sourcevalue}
,并在下面的示例中将其替换为{scrubbedvalue}
。我们不能在{sourcevalue}
上进行直接匹配,因为它是未知的,但其余的可以被引用。
有没有一种简单的方法可以使用mysql开箱即用?如果没有,有没有办法通过正则表达式匹配来获得匹配的起始位置和长度,并以这种方式替换?
示例输入:
<Attributes>
<Map>
...
<entry key="foo" value="{sourcevalue}"/>
...
</Map>
</Attributes>
示例输出:
<Attributes>
<Map>
...
<entry key="foo" value="{scrubbedvalue}"/>
...
</Map>
</Attributes>
答案 0 :(得分:1)
最好在插入之前完成清理数据。
如果字符串本身在一列中,那么一个简单的UPDATE
就可以了。
如果您使用的是MariaDB,请参阅REGEXP_REPLACE()
。
如果它隐藏在一个字符串中,你真的应该使用一些应用程序语言来修复代码。
答案 1 :(得分:1)
AFAIK Mysql不提供简单的“RegExp查找和替换”功能。
但是还有其他一些方法可以解决手头的问题:
选项#1
通过添加新的数据库表来规范化您的数据模式,例如: “属性”,带有“键”和“值”列,并将数据放入其中,而不是将其保留在XML“blob”中。
通过这种方式,您将能够使用常规SQL语法来查询和更新属性,并在必要时对其进行正确索引。
选项#2
如果#1不适合您(无论出于何种原因), 您可以尝试使用新的(Mysql 5.7+)XML functions,如下所示:
SELECT @xml:='<Attributes>
<Map>
<entry key="a" value="a"/>
<entry key="foo" value="{sourcevalue}"/>
<entry key="z" value="z"/>
</Map>
</Attributes>';
SELECT UpdateXML(
@xml,
'//entry[@key="foo"]/@value',
'value="{scrubbedvalue}"'
);
选项#3
如果#2对你不起作用(例如你正在运行旧版本的Mysql),你可以尝试使用原始字符串操作函数来实现相同的结果,例如:
SELECT @key:='foo';
SELECT
REPLACE(
@xml,
SUBSTRING(
@xml,
@s:=LOCATE('"',@xml,LOCATE(CONCAT('key="',@key,'"'),@xml)+LENGTH(@key)+6)+1,
LOCATE('"',@xml,@s+LENGTH(@key)+6)-@s),
"{scrubbedvalue}"
);
加上REGEXP过滤器(仅更新匹配的记录)
WHERE @xml REGEXP 'key="foo"';
但是如果你的XML块没有规范化并且可以采用不同的格式(即使用不同数量的空格,实体引用e.t.c。),你将不得不格外小心。
答案 2 :(得分:1)
出于文档目的,昨天我在等待答案时做了以下操作。
这不是很漂亮,可能会被改造成更干净的东西,但如果一切都失败了,它应该适用于其他人。
我本质上得到值的左侧,值的右侧,然后与新值连接并将其更新到db。
UPDATE mytable SET attributes =
CONCAT(
-- length of 'value="' is 7. Want 7-1 == 6
SUBSTRING(attributes, 1, LOCATE('value="', attributes, POSITION('foo' in attributes))+6), -- Left of value
'%%SCRUBBED_VALUE%%', -- Scrubbed value.
-- length of 'value="' is 7. Want 7 for next " reference.
SUBSTRING(attributes, LOCATE('"', attributes, LOCATE('value="', attributes, POSITION('foo' in attributes))+7), LENGTH(attributes) - LOCATE('"', attributes, LOCATE('value="', attributes, POSITION('foo' in attributes))+7) + 1) -- Right of Value
)
WHERE name = 'SomeUniqueIdentifier';