今天在工作中写项目的时候,遇到了一个让我感到几乎无解的问题,在转换了思路后,想出了一个折中的解决方案,记录如下。

其实,问题的场景,非常简单:

就是需要查询出上图的数据,红框是从 项目产品表 中查询的2个字段,绿框是从与项目产品表关联的 文章表 中查询出的1个字段。我希望实现的效果是,获取到项目产品对应的文章提交人数,即该项目产品,有多少人提交了文章。看似很简单啊,于是我开始撸 SQL 语句了。

先写个雏形

既然在查询项目产品表的时候,希望多查询1列数据,而此列数据是从其他关联表获取的,所以基本实现方式,是使用子查询。

SELECT s.id, s.name, (SELECT COUNT(*) FROM art_subject_article WHERE subject_id = s.id) AS article_num
FROM crm_subject s
ORDER BY article_num DESC;

获得结果如下:

这个 SQL 语句,查询出了项目产品所对应的文章数,下面基于它再做个优化调整,把查询到的文章数量 article_num 变为提交文章的用户数量 member_num。

再优化一下,意外发生了

现在不是直接从文章表中,获取文章数量了,而是需要先根据文章表中的用户ID进行分组,获得分组数据之后,再通过 count(*) 聚合函数,拿到用户数量。于是继续调整 SQL 如下:

SELECT s.id, s.name, (SELECT count(*) FROM (SELECT mg_userid FROM art_subject_article WHERE subject_id = s.id GROUP BY mg_userid) t) AS member_num
FROM crm_subject s
ORDER BY member_num DESC;

但是,运行却报错了:

报错信息说:s.id 字段找不到。这是一个嵌套的子查询,在嵌套的最内层的子查询中,关联外部表的字段,是无法关联的。虽然我没找根据,但通过报错信息,也能大致看出一二。而且,在 DataGrip 中,把鼠标放到 s.id 上面时,也会出现一个提示:

虽然这个提示,我也不甚明了,但是感觉上,好像就是在告诉我,你无法关联到外部表的字段。

好像无解了,转变思路,柳暗花明

上面的 SQL 语句,看起来是如此的完美,可是就是有问题、不成立,咋办?

突然,灵机一动,想到一个方案,姑且一试。既然在嵌套的最内层的子查询中,做 WHERE subject_id = s.id 与主表的字段关联行不通,那么,就不在内层的子查询中做关联,把它提到外层的子查询中去,不就行的通了嘛。于是,改造 SQL 如下:

SELECT s.id, s.name, (SELECT count(*) FROM (SELECT subject_id, mg_userid FROM art_subject_article GROUP BY subject_id, mg_userid) t WHERE t.subject_id = s.id) AS member_num
FROM crm_subject s
ORDER BY member_num DESC;

主要关注子查询这里的改造,我们可以把这里的子查询做个分解。

首先,可以把子查询看成这样:(SELECT count(*) FROM t WHERE t.subject_id = s.id) AS member_num,把它理解成从 t 表中查询与主表的项目产品有关的记录数量。

然后,我们再把 t 表看成 (SELECT subject_id, mg_userid FROM art_subject_article GROUP BY subject_id, mg_userid) t,代表从文章表中查询出每个产品对应的用户ID。

最后把2个子查询,整合起来,就实现了查询项目产品表中,每个产品所对应的提交了文章的用户数量。

有没有更好的解决方案

这个折中的方案,虽然可以解决我的问题,但是,我依然想知道,有没有更好的、更标准的最佳实践。

并且此方案,也有3点不足:

  1. 改进前我们是对文章表做项目产品关联查询后再分组,改进后是对文章表做全表扫描后的分组,效率较低,在大数据下的表现不好。

  2. 优化方案是基于两层嵌套的子查询进行的,假如需要三层嵌套的子查询,此方案估计又失效了。

  3. 此优化方案较为局限,不具有普适性,不能很好的适用于各种业务场景。

所以,我将我遇到的这个问题,和解决方案分享在此,希望能帮助到有缘人,同时,也期望各位大神能够不吝赐教,分享一下最佳实践。

关于 MySQL 嵌套子查询中,无法关联主表字段问题的折中解决方法的更多相关文章

  1. Mysql in子查询中加limit报错

    Mysql in子查询中加limit报错 select id from aa where id in ( select id from bb limit 10 ); 改写成 SELECT id FRO ...

  2. mysql更新子查询中的内容

    UPDATE t_finance_certify_copy c SET c.biz_type=2,c.sub_biz_type=18WHERE c.finance_certify_id IN(SELE ...

  3. laravel 迁移文件中修改含有enum字段的表报错解决方法

    解决方法: 在迁移文件中up方法最上方加上下面这一行代码即可: Schema::getConnection()->getDoctrineSchemaManager()->getDataba ...

  4. Mysql Join-连接查询(中)

    Mysql Join-连接查询(中) 认识 就我平时的数据接触来看, 连接查询也没有很复杂,不够是非常需要耐心和逻辑的, 一点点将数据查出来, 拼接等. 没有什么技巧, 多练习就会了. 无非就是表之间 ...

  5. mysql in 子查询 效率慢 优化(转)

    mysql in 子查询 效率慢 优化(转) 现在的CMS系统.博客系统.BBS等都喜欢使用标签tag作交叉链接,因此我也尝鲜用了下.但用了后发现我想查询某个tag的文章列表时速度很慢,达到5秒之久! ...

  6. MySQL 行子查询(转)

    MySQL 行子查询 行子查询是指子查询返回的结果集是一行 N 列,该子查询的结果通常是对表的某行数据进行查询而返回的结果集. 一个行子查询的例子如下: SELECT * FROM table1 WH ...

  7. MySQL FROM 子查询

    FROM 子句中的子查询 MySQL FROM 子查询是指 FROM 的子句作为子查询语句,主查询再到子查询结果中获取需要的数据.FROM 子查询语法如下: SELECT ... FROM (subq ...

  8. SQL相关子查询是什么?和嵌套子查询有什么区别?

    目录 两者的各种叫法 相关子查询MySQL解释 相关子查询Wikipedia解释 相关子查询执行步骤拆解 相关子查询和嵌套查询的区别 参考资料 两者的各种叫法 相关子查询叫做:Correlated S ...

  9. Mybatis 一对多延迟加载,并且子查询中与主表字段不对应 (19)

    Mybatis  一对多延迟加载,并且子查询中与主表字段不对应应用说明. 实现一对多关联(懒加载),一个教研组对应多个教师,既:教师的教研编号与教研组的教研编号关联,并且教师关联教研组外键与教研组编号 ...

  10. [SQL SERVER系列]之嵌套子查询和相关子查询

    子查询有两种类型,一种是只返回一个单值的子查询,这时它可以用在一个单值可以使用的地方,这时子查询可以看作是一个拥有返回值的函数:另外一种是返回一列值的子查询,这时子查询可以看作是一个在内存中临时存在的 ...

随机推荐

  1. 分布式存储系统之Ceph集群存储池、PG 与 CRUSH

    前文我们了解了ceph集群状态获取常用命令以及通过ceph daemon.ceph tell动态配置ceph组件.ceph.conf配置文件相关格式的说明等,回顾请参考https://www.cnbl ...

  2. 不安装运行时运行 .NET 程序 - NativeAOT

    大家好,先祝大家国庆快乐.不过大家看到这篇文章的时候估计已经过完国庆了 . 上一篇我们写了如何通过 SelfContained 模式发布程序(不安装运行时运行.NET程序)达到不需要在目标机器上安装 ...

  3. JS 可编辑表格的实现

    1.实现效果 用户点击语文,数学,英语部分的单元格,可以实现分数的编辑,总分也会随之变化.先看下效果,如图: 2.设计思路 先通过HTML5+CSS3绘制表格,添加input的样式和err提示动画. ...

  4. ClickHouse(10)ClickHouse合并树MergeTree家族表引擎之ReplacingMergeTree详细解析

    目录 建表语法 数据处理策略 资料分享 参考文章 MergeTree拥有主键,但是它的主键却没有唯一键的约束.这意味着即便多行数据的主键相同,它们还是能够被正常写入.在某些使用场合,用户并不希望数据表 ...

  5. RabbitMQ GUI客户端工具(RabbitMQ Assistant)

    RabbitMQ GUI客户端工具(RabbitMQ Assistant) 平时用控制台或者网页进行管理不免有点不方便,尤其在读取消息的时候不支持过滤和批量发送消息,在此推荐一个漂亮的GUI客户端工具 ...

  6. C#使用内存和指针方式将字节数组转换为Bitmap

    /// <summary> /// 指针方式转 /// </summary> /// <param name="Width">图像的宽</ ...

  7. 2022春每日一题:Day 37

    题目:[USACO14FEB]Auto-complete S 字典树套路题,字典树优化剪枝,加个cnt标记即可 代码: #include <cstdio> #include <cst ...

  8. scrapy框架命令

    scrapy startproject #创建scrapy项目 scrapy genspider test www.baidu.com #在项目下的spider目录下生成爬虫文件 test爬虫名称 w ...

  9. windows每日定时计划任务

    若要计划安全脚本 ,Sec.vbs,每天在下午 5:00 到上午 7:59 之间每隔 100 分钟在本地计算机上运行一次,请键入: schtasks /create /tn Security Scri ...

  10. 【云原生 · Kubernetes】Taint和Toleration(污点和容忍)

    个人名片: 因为云计算成为了监控工程师‍ 个人博客:念舒_C.ying CSDN主页️:念舒_C.ying Taint和Toleration(污点和容忍) 概念 添加多个tainit(污点) 使用例子 ...