2017-08-12 19 views
2

有沒有辦法寫一個優化版本的自我連接查詢我有下面? 我正在嘗試查找已註銷但訪問特定聊天室的用戶的聊天室會話活動,例如下面的示例SQL查詢中用戶輸入聊天室1和3並退出的用戶。使用SQL執行內部自連接的更好方法是什麼?

DROP TABLE IF EXISTS tbl; 
CREATE TABLE tbl (
    id BIGSERIAL PRIMARY KEY, 
    empno INT, 
    activity VARCHAR(50) 
); 

INSERT INTO tbl (empno, activity) VALUES 
(1, 'logged_in'), 
(1, 'chatroom1'), 
(1, 'chatroom3'), 
(2, 'logged_in'), 
(2, 'logged_out'), 
(1, 'logged_out'), 
(3, 'logged_in'), 
(3, 'chatroom5'); 

Select t1.* from 
(Select empno, activity from tbl where activity in ('chatroom1', 'chatroom3')) as t1 
JOIN 
(Select empno from tbl where activity ='logged_out') as t2 
ON 
t1.empno = t2.empno 

我用PostgreSQL寫了上面的腳本,但我正在尋找一種更好的方式來編寫SQL自連接。我想爲我可以使用CTE的子查詢。

+1

我刪除了不兼容的數據庫標籤。請僅使用您真正使用的數據庫進行標記。 –

+0

你可以將你的過濾器移動到加入條件:'...從tbl開始t1連接tbl作爲t2開始(t1.empno = t2.empno和t1.activity在('chatroom1','chatroom3')和t2。 );'我相信它會更「適合索引」(與Darshan Mehta答案相同)(https://stackoverflow.com/a/45645309/593144)) – Abelisto

回答

2

您還可以使用聚集。如果我理解正確:

select empno 
from tbl 
group by empno 
having sum((activity = 'logged_out')::int) > 0 and 
     sum((activity = 'chatroom1')::int) > 0 and 
     sum((activity = 'chatroom3')::int) > 0; 

如果你的意思要麼聊天室,而不是兩個,我會用:

having sum((activity = 'logged_out')::int) > 0 and 
     sum((activity in ('chatroom1', 'chatroom3'))::int) > 0 
+0

由於標準是至少有一個聊天室被訪問過,是不是應該在兩個聊天室中有一個或兩個之間的數額? – codeBarer

+1

@codeBarer。 。 。我解釋了這個問題 - 「進入聊天室1和3並已退出的用戶」 - 說用戶需要在聊天室中。但是你的解釋也是有道理的,所以我想我會在答案中加上這一點。 –

3

您可以使用下面的查詢:

SELECT t1.* 
FROM tbl t1 JOIN tbl t2 ON t1.empno = t2.empno 
WHERE t1.activity IN ('chatroom1', 'chatroom3') 
AND t2.activity ='logged_out'; 
相關問題