欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

mysql函数取代相关子查询(Correlated subquery)_MySQL

程序员文章站 2022-06-12 22:27:17
...
bitsCN.com


mysql函数取代相关子查询(Correlated subquery)

Sql代码

CREATE TABLE `20121105_teacher` (

`teacher_id` int(11) NOT NULL,

`school_id` int(11) NOT NULL,

PRIMARY KEY (`teacher_id`),

KEY `20121105_teacher_idx_school` (`school_id`)

) ENGINE=InnoDB

教师表,里面有1000个教师,随机分布在40个学校里

Sql代码

CREATE TABLE `20121105_subject_teacher_class` (

`teacher_id` int(11) NOT NULL,

`subj` varchar(10) NOT NULL,

`class` varchar(10) NOT NULL,

PRIMARY KEY (`teacher_id`,`subj`,`class`)

) ENGINE=InnoDB

教师任课科目表,教师随机在24个班级内随机教三个科目.为了方便演示,直接将科目名称和班级名称放到数据库中

假设要查询教师的授课情况,每个教师这样显示

英语:11班,12班,8班##语文:13班,1班,21班,6班##数学:12班,14班,6班,7班

很容易想到这个sql能把每个教师的授课情况显示出来

Sql代码

select tid,GROUP_CONCAT( cls SEPARATOR '##') c1 from

(

select teacher_id tid,CONCAT(subj,':',GROUP_CONCAT(class)) cls

from 20121105_subject_teacher_class stc

GROUP BY teacher_id,subj

) t GROUP BY tid,

那么把这个作为一个子查询呢?似乎很容易想到

Sql代码

select teacher_id,

(

select GROUP_CONCAT( cls SEPARATOR ' ## ') from

(

select teacher_id tid,CONCAT(subj,':',GROUP_CONCAT(class)) cls

from 20121105_subject_teacher_class stc where stc.teacher_id=t1.teacher_id

GROUP BY teacher_id,subj) t GROUP BY tid

)

from 20121105_teacher t1 where school_id=2

不过可惜在最里面那层子查询已经无法引用最外层的t1表的teacher_id这个字段了,

只能拿到外面一层

Sql代码

select teacher_id,

(

select GROUP_CONCAT( cls SEPARATOR ' ## ') from

(

select teacher_id tid,CONCAT(subj,':',GROUP_CONCAT(class)) cls

from 20121105_subject_teacher_class stc

GROUP BY teacher_id,subj) t where t.tid=t1.teacher_id GROUP BY tid

)

from 20121105_teacher t1 where school_id=2

不过因为这样无法高效利用索引,这个sql花了0.05s

所以可以建个函数

Sql代码

CREATE FUNCTION `20121105f`(p_teacher_id int) RETURNS varchar(2000)

READS SQL DATA

BEGIN

DECLARE v_result VARCHAR(2000);

DECLARE EXIT HANDLER for not found return null;

select GROUP_CONCAT( cls SEPARATOR ' ## ') into v_result from

(

select teacher_id tid,CONCAT(subj,':',GROUP_CONCAT(class)) cls

from 20121105_subject_teacher_class stc where stc.teacher_id=p_teacher_id

GROUP BY teacher_id,subj

) t GROUP BY tid;

return v_result;

END

然后这样用

Sql代码

select SQL_NO_CACHE teacher_id,

20121105f(teacher_id)

from 20121105_teacher t1 where school_id=2

马上成瞬时的了.

不用子查询,也可以用左连接的方法

Sql代码

select t1.teacher_id,t2.c1

from 20121105_teacher t1

left join (

select tid,GROUP_CONCAT( cls SEPARATOR '##') c1 from

(

select teacher_id tid,CONCAT(subj,':',GROUP_CONCAT(class)) cls

from 20121105_subject_teacher_class stc

GROUP BY teacher_id,subj

) t GROUP BY tid

) t2

on t1.teacher_id=t2.tid

where school_id=2

这种情况下因为20121105_subject_teacher_class表没用索引,是0.04s左右

加上条件

Sql代码

select t1.teacher_id,t2.c1

from 20121105_teacher t1

left join (

select tid,GROUP_CONCAT( cls SEPARATOR '##') c1 from

(

select stc.teacher_id tid,CONCAT(subj,':',GROUP_CONCAT(class)) cls

from 20121105_subject_teacher_class stc ,20121105_teacher te

where stc.teacher_id=te.teacher_id and te.school_id=2

GROUP BY stc.teacher_id,subj

) t GROUP BY tid

) t2

on t1.teacher_id=t2.tid

where school_id=2

这样这个也成了瞬时的,不过筛选teacher的条件(school_id=2)执行了两次,

如果这个条件比较耗资源,应该就更慢了

bitsCN.com
相关标签: mysql