/*Tables:*/
SELECT tid, SID FROM t_s_map;/*student id whom teacher has access*/
SELECT sgid FROM sg;/* student_group table*/
SELECT sgid, SID FROM sgm;/*student group members table(info of students under student group)*/
/*Note: All columns are id and have values > 0*/
示例数据:
Table: sg
sgid
101
201
Table: sgm
sgid sid
101 1
101 2
101 3
201 1
201 2
Table: t_s_map
tid sid
11 1
11 2
11 3
22 1
22 2
问题陈述:
获取教师可以访问的学生组列表(如果教师可以访问学生组下的所有学生,那么只有该学生组可以访问)。 因此,tid = 11可访问的学生组是sgid = 101和sgid = 201,而tid = 22则是sgid = 201。
SELECT sg.sgid
FROM sg
JOIN sgm
ON (sg.sgid = sgm.sgid)
LEFT OUTER JOIN t_s_map
ON (sgm.SID = t_s_map.SID)
WHERE t_s_map.tid = 22
GROUP BY sg.sgid
HAVING MAX (NVL(t_s_map.SID, 0)) > 0 AND MIN (NVL(t_s_map.SID, 0)) > 0;
现在上面的查询工作正常,但速度很慢,有没有其他(更快)方法可以做到。
当前版本:
SELECT sgm.sgid
FROM sgm
LEFT OUTER JOIN t_s_map
ON (sgm.SID = t_s_map.SID)
WHERE t_s_map.tid = 22
GROUP BY sgm.sgid
HAVING MIN (NVL(t_s_map.SID, 0)) > 0;
答案 0 :(得分:1)
您没有发布样本数据,所以我无法尝试。 你能看到这个查询吗?它应该等同于您在上面发布的那个。
由于您使用了WHERE t_s_map.id,因此LEFT JOIN相当于INNER JOIN。
此外,在我看来,你的HAVING条件不是必需的(SID应该总是有一个值> 0。我最后一点错了吗?)
SELECT DISTINCT sg.sgid
FROM sg
INNER JOIN sgm ON sg.sgid = sgm.sgid
INNER JOIN t_s_map ON sgm.SID= t_s_map.SID
WHERE t_s_map.tid = 1234;
<强>更新强>
关注“问题陈述”我认为你的(上面也是我的)是被问到的。 下一个查询可以。
SELECT TID, C.SGID
FROM t_s_map B
LEFT JOIN SGM C ON B.SID = C.SID
LEFT JOIN (SELECT sgid, COUNT(*) AS RC FROM SGM GROUP BY sgid) D ON C.SGID = D.SGID
GROUP BY TID, C.SGID, RC
HAVING COUNT(*) = RC;
第二次更新 我想您可以很容易地发现只获取SGID,您可以将上述查询修改为:
SELECT DISTINCT C.SGID
FROM t_s_map B
LEFT JOIN SGM C ON B.SID = C.SID
LEFT JOIN (SELECT sgid, COUNT(*) AS RC FROM SGM GROUP BY sgid) D ON C.SGID = D.SGID
GROUP BY TID, C.SGID, RC
HAVING COUNT(*) = RC;
答案 1 :(得分:1)
你没有做left join
。您的where
子句将其转换为inner join
。所以,从:
SELECT sg.sgid
FROM sg JOIN
sgm
ON sg.sgid = sgm.sgid JOIN
t_s_map
ON sgm.SID = t_s_map.SID
WHERE t_s_map.tid = 1234
GROUP BY sg.sgid
HAVING MAX(t_s_map.SID) > 0 AND MIN(COALESCE(t_s_map.SID, 0)) > 0;
接下来,不需要join
到sg
。
SELECT sgm.sgid
FROM sgm JOIN
t_s_map
ON sgm.SID = t_s_map.SID
WHERE t_s_map.tid = 1234
GROUP BY sgm.sgid
HAVING MAX(t_s_map.SID) > 0 AND MIN(COALESCE(t_s_map.SID, 0)) > 0;
此查询可以利用t_s_map(tid, sid)
和sgm(sgid)
上的索引。
答案 2 :(得分:0)
根据SQL查询的执行顺序,首先执行From和Joins,然后执行Where子句。尝试使用以下查询来减少过滤器的行数。你可以相应地添加你的小组并拥有条款。
SELECT sg.sgid
FROM sg
JOIN sgm
ON (sg.sgid = sgm.sgid)
LEFT OUTER JOIN (select SID from t_s_map
where t_s_map.tid = 1234) tmp
on (sgm.SID = tmp.SID)
答案 3 :(得分:-1)
您无需包含sg
表格,WHERE
和HAVING
条款有效地将LEFT OUTER JOIN
转换为INNER JOIN
,您不需要检查自MAX
后的MAX >= MIN
值以及MIN > 0
然后MAX >= MIN > 0
,NVL
和0 > 0
都不需要NULL > 0
不是真的。
SELECT sgm.sgid
FROM sgm
INNER JOIN t_s_map
ON ( sgm.SID = t_s_map.SID )
WHERE t_s_map.tid = 1234
GROUP BY sgm.sgid
HAVING MIN(t_s_map.SID) > 0;