2017-10-06 67 views
0
/*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

您是否嘗試過向表中添加索引?這可以加快查詢速度。 –

+0

請注意,您的左連接完全沒有意義,因爲您將謂詞應用於外連接到的表:「where t_s_map.tid = 1234」 –

+0

您不需要'MAX',因爲如果MIN> 0,則MAX > = MIN> 0' – MT0

回答

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; 
+0

添加樣本數據 – L30n1d45

+0

@ L30n1d45您是否嘗試過我的第二個查詢? – etsa

+0

這不是要求:對於tid作爲輸入我想要可訪問的sgid列表作爲輸出。 – L30n1d45

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; 

接下來,joinsg是沒有必要的。

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)優勢的指標。

+0

'MIN(t_s_map.SID,0)'中的參數太多 - 您需要刪除',0'。 – MT0

+0

這不是內連接。 – L30n1d45

+0

@ L30n1d45。 。 。編寫它時可能不是「內部連接」。當它運行並處理「where」條件時,它是一個「內部連接」。 –

-1

你並不需要包括sg表中,WHEREHAVING條款有效打開LEFT OUTER JOININNER JOIN,你並不需要檢查,因爲MAX >= MINMAX值,如果MIN > 0然後MAX >= MIN > 0,你不需要NVL因爲0 > 0NULL > 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; 
+0

Downvoter關心評論? – MT0

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) 
+0

使用子查詢替代t_s_map表和where子句 –