PAYATHON 2026

MariaDB 如何统计两个等长字符串中位置相同的字符?

数据小陈

结论

逐个比较两个字符串相同位置上的字符,再用相等字符的数量除以字符串长度,就能算出匹配比例。keyboard 和 ekyboard 有 6 个位置的字符相同,因此匹配比例为 6 / 8 = 75%。

对这个需求,按位置逐字符比较即可。下面的递归 CTE 示例适用于支持递归 CTE 的 MariaDB 版本:

WITH RECURSIVE positions (i) AS (
    SELECT 1
    UNION ALL
    SELECT i + 1
    FROM positions
    WHERE i < CHAR_LENGTH('keyboard')
)
SELECT
    SUM(
        BINARY SUBSTRING('keyboard', i, 1)
        = BINARY SUBSTRING('ekyboard', i, 1)
    ) AS matching_chars,
    100.0 * SUM(
        BINARY SUBSTRING('keyboard', i, 1)
        = BINARY SUBSTRING('ekyboard', i, 1)
    ) / CHAR_LENGTH('keyboard') AS matching_percent
FROM positions;

结果是 matching_chars = 6,matching_percent = 75.0000。CHAR_LENGTH 按字符计算长度。BINARY 会按字符本身进行比较,避免不区分大小写的排序规则将大小写不同的字符视为相等。

用于正则匹配结果

问题中的 r_str 是由字符类组成的正则表达式。找到匹配文本的起始位置后,可以取出与 str 等长的片段,再逐位比较。下面是结构示意,表名和字段名需要替换为实际名称。这里假设 search_terms.id 和 addresses.id 是唯一键:

WITH RECURSIVE
candidate AS (
    SELECT
        a.id AS address_id,
        t.id AS term_id,
        a.noun,
        t.str,
        REGEXP_INSTR(a.noun, t.r_str) AS loc
    FROM addresses AS a
    JOIN search_terms AS t
      ON a.noun RLIKE t.r_str
),
walk (address_id, term_id, noun, str, loc, i, matched) AS (
    SELECT address_id, term_id, noun, str, loc, 1, 0
    FROM candidate
    WHERE loc > 0
      AND CHAR_LENGTH(str) > 0

    UNION ALL

    SELECT
        address_id,
        term_id,
        noun,
        str,
        loc,
        i + 1,
        matched + (
            BINARY SUBSTRING(str, i, 1)
            = BINARY SUBSTRING(noun, loc + i - 1, 1)
        )
    FROM walk
    WHERE i <= CHAR_LENGTH(str)
)
SELECT
    address_id,
    term_id,
    noun,
    str,
    loc,
    matched AS matching_chars,
    100.0 * matched / CHAR_LENGTH(str) AS percentage
FROM walk
WHERE i = CHAR_LENGTH(str) + 1;

matched 表示正则命中的片段与原字符串在相同位置上相等的字符数。可以将最终结果与 priority=1 的精确匹配结果合并,再按优先级、匹配比例和位置排序,例如使用 ORDER BY priority ASC, percentage DESC, loc ASC。

注意事项

  • 这个计算要求正则匹配片段的长度与 str 的字符长度一致。如果正则可能匹配不同长度的文本,应先确定取哪段文本以及如何对齐。
  • 空字符串没有可计算的百分比,示例会将其排除。REGEXP_INSTR 返回 0 表示没有匹配,不能将其作为有效起始位置。
  • 查询中的 GROUP BY noun 同时选择了多个未聚合字段。启用 ONLY_FULL_GROUP_BY 时,查询可能报错;关闭该选项时,非分组字段的取值也可能不符合预期。应先确定每个 noun 要保留哪条结果,再进行分组或排序。

备注:内容仅供参考。