我的Ubuntu Web开发系统最近从19.04更新到19.10,其中包括MySQL的更新,当前版本为8.0.18。实时服务器的版本为5.6.45(它是运行CentOS的共享服务器,因此我无法更改它),我发现REGEXP中的某些内容显然已随更新而更改。
以下查询在本地运行时,会将非法参数赋予正则表达式,但可以在实时服务器上正常运行。我不太熟悉正则表达式,更不用说MySQL中的REGEXP了,那么我如何才能在较新的MySQL中做到这一点而又不破坏旧的呢?
这是它们的两条REGEXP行,其后是完整的查询。
REGEXP '[[:<:]][0-9]+(-[0-9]+)*[[:>:]]'
REGEXP '^[0-9]+(-[0-9]+)*$'
SELECT t.ID AS partID, t.partNo,
TRIM(CONCAT(
IF(N.n = 0, '', LEFT(t.Model, 2)),
SUBSTRING_INDEX(SUBSTRING_INDEX(t.Model, '-', N.n + 1), '-', -1)
)) AS modelNo, NULL AS bodyNo, t.xHD AS isRHD
FROM (
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(t.part, ' ', N.n + 1), ' ', -1) AS Model,
CASE LEFT(t.part, 3) WHEN 'LHD' THEN 1 WHEN 'RHD' THEN 2 ELSE 0 END AS xHD,
t.ID, t.GroupNumber, t.partNo, t.Models
FROM (
SELECT
LTRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(p.Models, ';', N.n + 1), ';', -1)) part,
p.ID, p.GroupNumber, p.partNo, p.Models
FROM parts_listing AS p CROSS JOIN parts_temp AS N
WHERE Models REGEXP '[[:<:]][0-9]+(-[0-9]+)*[[:>:]]' AND
N.n <= LENGTH(Models) - LENGTH(REPLACE(Models, ';', ''))
) AS t CROSS JOIN parts_temp AS N
WHERE N.n <= LENGTH(t.part) - LENGTH(REPLACE(t.part, ' ', ''))
) AS t CROSS JOIN parts_temp AS N
WHERE t.Model REGEXP '^[0-9]+(-[0-9]+)*$' AND
N.n <= LENGTH(t.model) - LENGTH(REPLACE(t.Model, '-', ''));
最佳答案
引入的MySQL 8.0.4将其regexes引擎的实现从Henry Spencer的实现更改为Unicode国际组件(ICU)。这涉及到一些非向后兼容的更改,这些更改在in the documentation中列出。这是您的用例感兴趣的部分:
Spencer库支持单词开头和单词结尾边界标记([[:<:]]
和[[:>:]]
表示法)。 ICU没有。对于ICU,您可以使用\b
来匹配单词边界。将反斜杠加倍,因为MySQL会将其解释为字符串中的转义字符。
换句话说,以下正则表达式在MySQL 8.0.4及更高版本中无效:'[[:<:]][0-9]+(-[0-9]+)*[[:>:]]'
,因为它包含亨利·斯宾塞(Henry Spencer)的boudary标记。
我如何才能在较新的MySQL中做到这一点而又不破坏旧的呢?
简短答案:您不能。更改不向后兼容。您可以通过定义一个自定义表达式(或字符类)来解决这种情况,该自定义表达式表示您的用例的单词边界。这是一个极其简化的版本,可以处理空格或字符串的开头/结尾:
'(^|\s)[0-9]+(-[0-9]+)*(\s|$)