当前位置: 首页 > news >正文

多对多关联查询

在 PostgreSQL 中,使用多对多关联表查询文档并将多个标签合并为逗号分隔的字符串,标准且高效的做法是使用聚合函数string_agg()

下面提供生产级完整方案,包含核心 SQL、分页避坑指南、Java/MyBatis 映射


📦 一、核心 SQL 实现

SELECT d.id, d.title, d.create_time, -- 核心:聚合标签为逗号分隔字符串 COALESCE(string_agg(t.name, ',' ORDER BY t.id), '') AS tag_list FROM documents d LEFT JOIN doc_tags dt ON d.id = dt.doc_id LEFT JOIN tags t ON dt.tag_id = t.id GROUP BY d.id, d.title, d.create_time ORDER BY d.create_time DESC;

📌关键说明

函数/语法作用
LEFT JOIN保证没有标签的文档也能查出(不会因INNER JOIN被过滤)
string_agg(t.name, ',' ORDER BY t.id)将多行标签名拼接成"Java,Spring,PostgreSQL"ORDER BY保证每次顺序一致
COALESCE(..., '')无标签时返回空字符串""而非NULL,方便前端处理
GROUP BY必须包含所有非聚合字段(PG 严格要求)

⚠️ 二、生产环境分页正确写法(必看)

直接在上面 SQL 加LIMIT/OFFSET会触发分页陷阱JOIN会先产生笛卡尔积再GROUP BY,导致LIMIT计算错误且性能骤降。

正确做法:先分页,再关联聚合

WITH paged_docs AS ( -- 1. 先按条件筛选并分页(仅取文档主表) SELECT id, title, create_time FROM documents WHERE title ILIKE '%搜索词%' ORDER BY create_time DESC LIMIT 10 OFFSET 0 ) -- 2. 仅对分页后的 10 条文档关联标签并聚合 SELECT pd.id, pd.title, pd.create_time, COALESCE(string_agg(t.name, ',' ORDER BY t.id), '') AS tag_list FROM paged_docs pd LEFT JOIN doc_tags dt ON pd.id = dt.doc_id LEFT JOIN tags t ON dt.tag_id = t.id GROUP BY pd.id, pd.title, pd.create_time;

💡 此写法在万级数据下仍能保持O(1)分页性能,是互联网项目标准实践。


☕ 三、Java + MyBatis 映射示例

1. DTO 定义
@Data public class DocumentDTO { private Long id; private String title; private LocalDateTime createTime; private String tagList; // "Java,Spring,PostgreSQL" }
2. Mapper XML
<select id="pageDocuments" resultType="com.yourpkg.DocumentDTO"> WITH paged_docs AS ( SELECT id, title, create_time FROM documents <where> <if test="keyword != null and keyword != ''"> AND title ILIKE CONCAT('%', #{keyword}, '%') </if> </where> ORDER BY create_time DESC LIMIT #{limit} OFFSET #{offset} ) SELECT pd.id, pd.title, pd.create_time, COALESCE(string_agg(t.name, ',' ORDER BY t.id), '') AS tag_list FROM paged_docs pd LEFT JOIN doc_tags dt ON pd.id = dt.doc_id LEFT JOIN tags t ON dt.tag_id = t.id GROUP BY pd.id, pd.title, pd.create_time </select>
3. Service 层处理(可选:转为 List)

如果业务需要List<String>而非字符串,可在 Java 层简单转换:

documentDTO.setTags( dto.getTagList().isEmpty() ? Collections.emptyList() : Arrays.asList(dto.getTagList().split(",")) );

🚀 四、性能优化建议

优化点实施方案
必建索引CREATE INDEX idx_doc_tags_doc ON doc_tags(doc_id);<br>CREATE INDEX idx_doc_tags_tag ON doc_tags(tag_id);
标签过滤若需“按标签筛选文档”,在WHERE中加AND EXISTS (SELECT 1 FROM doc_tags dt2 JOIN tags t2 ON dt2.tag_id=t2.id WHERE dt2.doc_id=d.id AND t2.name IN ('Java')),避免JOIN膨胀
大数据量单文档标签 >50 时,string_agg内存开销上升,建议改用应用层组装(查文档 → 批量查标签 → JavaMap<Long, List<String>>分组)
去重需求若关联表数据异常导致重复标签,改用string_agg(DISTINCT t.name, ',' ORDER BY t.name)

💡 扩展:如果想返回 JSON 数组而非逗号字符串?

PostgreSQL 原生支持,前端解析更方便:

-- 替换 string_agg 部分 COALESCE(json_agg(t.name ORDER BY t.id) FILTER (WHERE t.name IS NOT NULL), '[]'::json) AS tags_json -- 结果: ["Java","Spring"]

如果你需要:

  1. 标签筛选 + 分页 + 聚合的完整 SQL
  2. JPA / MyBatis-Plus 的等价实现
  3. 标签高亮或权重排序逻辑
http://www.jsqmd.com/news/676127/

相关文章:

  • 揭秘2026苹果仓太空仓靠谱厂商,定制安装公司哪家好 - mypinpai
  • 从自动售货机到芯片验证:手把手拆解BDD如何把指数级问题‘压扁’
  • 2026年企业级性能测试平台评测:稳定性、信创与协同能力解析
  • 2026年好用的散热器推荐,非标定制解决特殊需求 - myqiye
  • 终极指南:如何在Blender中轻松导入导出3MF文件
  • 15 ComfyUI 实战:一文看懂 Apply ControlNet 的 3 个核心参数
  • 梳理海象皇宫冰淇淋公司,海象皇宫雪糕性价比哪家高 - 工业品网
  • Legacy iOS Kit终极指南:让旧iPhone/iPad重获新生的神器
  • 2026年靠谱的知识产权公司推荐,聊聊如何办知识产权转让与注册 - mypinpai
  • 别再让OCV拖慢你的芯片!手把手教你用set_timing_derate优化时序(附CPPR实战)
  • 扩散模型太抽象?试试从‘分数’视角理解SGM:一个直觉化的Langevin动力学采样指南
  • 2026年LED显示屏供应商推荐:综合实力测评,高性价比品牌选型指南 - 速递信息
  • 2025租车公司推荐:1亿+用户验证,6家平台在「车型价格保障」三维度谁更值得选? - 科技焦点
  • HsMod插件框架的模块化架构设计与实现原理深度解析
  • 为什么92%的Dify边缘项目在v2026.1.0-beta后崩溃?深度解析OCI镜像签名验证机制变更
  • 2026年雷达液位计厂家推荐深度测评:如何为你的工业场景匹配最佳方案 - 速递信息
  • 思源宋体TTF终极指南:免费商用字体如何让中文设计焕然一新
  • 越努力越糟糕?揭秘四大护肤误区,AI 如何帮你从“乱炖式”护肤回归科学变美
  • 从Arduino到STM32:手把手教你将GRBL固件移植到STM32F446RE开发板(附引脚映射避坑指南)
  • 北京企业团建服务商推荐:五家主流品牌 - 品牌策略主理人
  • 关于auto,float和父级塌陷的困惑点
  • 终极B站缓存视频合并方案:一键导出完整MP4,弹幕完美保留
  • 前端+AI项目学习笔记day12
  • 常熟出租房消防升级:智能无线火灾报警系统首选立可安 - 今日热点
  • Premiere调色进阶:手把手教你用‘HSL辅助’和‘颜色匹配’,搞定人物肤色与多镜头统一
  • 思源宋体CN:7种字重免费开源字体如何快速提升你的中文设计效果
  • 别再只用PCA了!用sklearn的Isomap处理‘瑞士卷’这类非线性数据,实战避坑指南
  • 5分钟快速上手:用罗技鼠标宏掌控PUBG武器后坐力的完整指南
  • 从ETOPO1数据到精美地形图:手把手教你用Matlab和m_map绘制专业级海底地形
  • 深聊自动变速箱维修企业怎么选,服务不错的企业有哪些 - 工业品网