You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写SQL实现多表关联并拆分service列的多值数据?

多表关联+逗号分隔列拆分的完整SQL方案

核心思路是先完成三表关联得到包含service列的数据集,再对该列的逗号分隔值进行拆分,将每个值转为单独行。以下分主流数据库给出具体实现:

MySQL 8.0+(推荐用JSON_TABLE)

利用JSON函数将逗号分隔字符串转为JSON数组,再通过JSON_TABLE展开为多行:

WITH joined_data AS (
    SELECT 
        o.org_id,
        o.org_name,
        c.city_name,
        r.relation_type,
        o.service
    FROM Organization o
    JOIN Relation r ON o.org_id = r.org_id
    JOIN City c ON r.city_id = c.city_id
)
SELECT 
    jd.org_id,
    jd.org_name,
    jd.city_name,
    jd.relation_type,
    TRIM(JSON_UNQUOTE(json_value)) AS service
FROM joined_data jd
JOIN JSON_TABLE(
    CONCAT('["', REPLACE(jd.service, ',', '","'), '"]'),
    '$[*]' COLUMNS(json_value VARCHAR(255) PATH '$')
) AS jt
WHERE jd.service IS NOT NULL AND jd.service != '';

MySQL 5.x(无JSON_TABLE,用递归CTE)

对于不支持JSON函数的老版本,用递归方式逐次拆分字符串:

WITH RECURSIVE joined_data AS (
    SELECT 
        o.org_id,
        o.org_name,
        c.city_name,
        r.relation_type,
        o.service,
        1 AS pos,
        SUBSTRING_INDEX(o.service, ',', 1) AS single_service,
        SUBSTRING(o.service, LENGTH(SUBSTRING_INDEX(o.service, ',', 1)) + 2) AS remaining_service
    FROM Organization o
    JOIN Relation r ON o.org_id = r.org_id
    JOIN City c ON r.city_id = c.city_id
    WHERE o.service IS NOT NULL AND o.service != ''
    UNION ALL
    SELECT 
        org_id,
        org_name,
        city_name,
        relation_type,
        service,
        pos + 1,
        SUBSTRING_INDEX(remaining_service, ',', 1),
        SUBSTRING(remaining_service, LENGTH(SUBSTRING_INDEX(remaining_service, ',', 1)) + 2)
    FROM joined_data
    WHERE remaining_service IS NOT NULL AND remaining_service != ''
)
SELECT 
    org_id,
    org_name,
    city_name,
    relation_type,
    TRIM(single_service) AS service
FROM joined_data
ORDER BY org_id, pos;

PostgreSQL

用string_to_array将字符串转为数组,再通过UNNEST展开:

SELECT 
    o.org_id,
    o.org_name,
    c.city_name,
    r.relation_type,
    TRIM(s.service) AS service
FROM Organization o
JOIN Relation r ON o.org_id = r.org_id
JOIN City c ON r.city_id = c.city_id
JOIN UNNEST(string_to_array(o.service, ',')) AS s(service) ON TRUE
WHERE o.service IS NOT NULL AND o.service != '';

SQL Server 2016+

使用官方内置的STRING_SPLIT函数,配合CROSS APPLY展开:

SELECT 
    o.org_id,
    o.org_name,
    c.city_name,
    r.relation_type,
    TRIM(s.value) AS service
FROM Organization o
JOIN Relation r ON o.org_id = r.org_id
JOIN City c ON r.city_id = c.city_id
CROSS APPLY STRING_SPLIT(o.service, ',') s
WHERE o.service IS NOT NULL AND o.service != '';

关键注意事项

  • 过滤空值:通过WHERE条件排除service为空或空字符串的行,避免生成无效空行
  • 清理空格:用TRIM处理拆分后的值,避免原字符串中逗号前后的空格残留
  • 老版本兼容:如果使用极老版本数据库(如MySQL 5.x之前),可能需要自定义拆分函数替代递归CTE

内容的提问来源于stack exchange,提问作者Sprössling

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 17:17:29