2015-11-04 80 views
1

我的表看起來像這樣選擇不同於加入

 
Table 1    Table 2 
Users     Options 

id name    id  user_id option 
-------    --- -------- -------- 
1 Donald    1  1   access1 
2 John    2  1   access2 
3 Bruce    3  1   access3 
4 Paul    4  2   access1 
5 Ronald    5  2   access3 
6 Steve    6  3   access1 

現在,我要選擇加入這些發現其中只有access1用戶 如果我這樣做

select t1.id,t1.name,t2.id,t2.user_id,t2.option 
from table1 t1, table2 t2 
where t1.id=t2.user_id 
and option='access1'; 

這不給我獨特的結果,因爲在這個例子中,我只需要user_id = 3我的數據已經有這些在數百

我也嘗試過類似

select user_id from table2 where option='access1' 
and user_id not in (select user_id from table2 where option<>'access1') 

還有其他不成功的嘗試過,但我堅持在這裏

回答

2

您可以使用EXISTS子查詢(技術上,左半連接)執行此操作:

SELECT id, name 
FROM table1 
WHERE EXISTS(
    SELECT * FROM table2 
    WHERE table1.id = table2.user_id 
     AND table2.option = 'access1' 
) 

如果您只想要具有access1而不具有任何其他訪問權的用戶,請添加NOT EXISTS(左反半連接;有一個詞來你的同事留下深刻的印象!):

AND NOT EXISTS (
    SELECT * FROM table2 
    WHERE table1.id = table2.user_id 
     AND table2.option <> 'access1' 
) 
+0

謝謝,我會馬上試試。 – srednivashtar

+0

我試過了,不存在選擇在這個方案給我0行 – srednivashtar

+0

有了一些變化又試了一次,在NOT EXISTS我用'AND NOT EXISTS( SELECT * FROM表2 WHERE = table1.id table2.user_id 和Table 。選項='access1''這似乎工作,但我還沒有驗證數據尚未 – srednivashtar

0

如果你想有隻access1用戶,我會用聚合:

select user_id 
from table2 
group by user_id 
having min(option) = max(option) and min(option) = 'access1'; 
+0

這不返回的名稱,並沒有加入到表的主鍵(我們不知道正在執行參照完整性)。這也是相當昂貴的,因爲像這樣計算列的最小值和最大值需要排序或建立臨時表。 – cliffordheath

+0

我同意@cliffordheath聚合對我來說會很貴,但是我會盡量試試 – srednivashtar

+0

我使用了聚合,它也返回了0行 – srednivashtar

0
WITH users(id,name) AS (VALUES 
    (1,'Donald'), 
    (2,'John'), 
    (3,'Bruce'), 
    (4,'Paul'), 
    (5,'Ronald'), 
    (6,'Steve') 
), options(id,user_id,option) AS (VALUES 
    (1,1,'access1'), 
    (2,1,'access2'), 
    (3,1,'access3'), 
    (4,2,'access1'), 
    (5,2,'access3'), 
    (6,3,'access1') 
), user_access_count AS (
    SELECT op.user_id,count(op.option) AS access_count 
    FROM options op 
    WHERE EXISTS(
    SELECT 1 FROM options 
    WHERE option = 'access1' 
) 
    GROUP BY op.user_id 
) 
SELECT u.id,u.name 
FROM users u 
INNER JOIN user_access_count uac ON uac.user_id = u.id 
WHERE uac.access_count = 1; 
1

bool_and變得非常簡單

with users (id,name) as (values 
    (1,'donald'), 
    (2,'john'), 
    (3,'bruce'), 
    (4,'paul'), 
    (5,'ronald'), 
    (6,'steve') 
), options (id,user_id,option) as (values 
    (1,1,'access1'), 
    (2,1,'access2'), 
    (3,1,'access3'), 
    (4,2,'access1'), 
    (5,2,'access3'), 
    (6,3,'access1') 
) 
select u.id, u.name 
from 
    users u 
    inner join 
    options o on o.user_id = u.id 
group by 1, 2 
having bool_and(o.option = 'access1') 
; 
id | name 
----+------- 
    3 | bruce