2011-12-18 7 views
1

データベースには、roles_usersという名前のテーブルがあります。これは、ユーザーが持つすべての役割を保持します。ここには、user_id、role_idという2つの列があります。SQL:NOT IN INクエリ

余分な役割を持たない通常のユーザーは、この表に1行あります。この行にはrole_idが1つあります。

管理者は、この表に2行あります。このようROLE_ID 2

とROLE_ID 1、および1行でワン:

user_id role_id 
88  1 
88  2 
99  1 // Only one row with that user_id, so he's a user 

今存在するどのように多くのユーザー/管理者/販売者/パートナーカウントしようとしてイム。

売り手は、3行、ROLE_ID 1のものを持っているので、私は試した4

ROLE_ID、2をROLE_IDとパートナーが1をROLE_IDた3

ROLE_IDこの:

SELECT user_id FROM roles_users WHERE role_id IN (1) // MEMBERS ONLY 
SELECT user_id FROM roles_users WHERE role_id IN (1,2) // ADMIN 
SELECT user_id FROM roles_users WHERE role_id IN (1,2,3) // SELLER 
SELECT user_id FROM roles_users WHERE role_id IN (1,4) // PARTNERS 

しかし、これらのクエリ正しく動作しません。彼らは私に、それが想定されているよりも終わったカウントを与える。そして、私はこれがすべての行を排除しないためだと信じている

私は、任意の行role_id 1とそれはthats。

どうすればいいですか?したがって、メンバーを調べるときに、user_idに2,3,4

+0

select distinct user_Id – Sparky

+0

あなたが必要とする関係演算子は[division](http://en.wikipedia.org/wiki/Relational_algebra#Division_.28.C3.B7.29)です。これは[サプライヤー誰がすべての部品を供給するのか」(http://www.dbdebunk.com/page/page/772076.htm)。推奨される読書[ここ](http://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/)、[ここ](http: //www.dbdebunk.com/page/page/772076.htm)および[here](http://www.cs.arizona.edu/~mccann/research/divpresentation.pdf)を参照してください。 – onedaywhen

答えて

0

のような行がないことを確認する必要があります。これにより、テーブル内の特権のすべての組み合わせがカウントされます

売り手とパートナーに関する
SELECT 
    COUNT(*) AS num 
    GROUP_CONCAT(role_id ORDER BY role_id) AS privilegeset 
FROM roles_users 
GROUP BY user_id 
+0

ええ!それは本当に機能しますか?この背後にある論理を説明するケア? – fge

0


私の理解では、売り手はrole_id = 3やパートナーが正しいrole_id = 4を持つことができる唯一のもので持つことができる唯一のものですか?

はい場合は、売り手とパートナーを見つけることは非常に簡単です:

SELECT user_id FROM roles_users WHERE role_id = 3 // SELLER 
SELECT user_id FROM roles_users WHERE role_id = 4 // PARTNERS 
0

ここでうまくいけば、任意のSQLで動作参加ベースのソリューションです。

SELECT user_id FROM roles_users RU0 
LEFT JOIN roles_users RU1 ON RU0.user_id = RU1.user_id AND RU1.role_id = 1 
LEFT JOIN roles_users RU2 ON RU0.user_id = RU2.user_id AND RU2.role_id = 2 
LEFT JOIN roles_users RU3 ON RU0.user_id = RU3.user_id AND RU3.role_id = 3 
LEFT JOIN roles_users RU4 ON RU0.user_id = RU4.user_id AND RU4.role_id = 4 
WHERE RU1.user_id IS NOT NULL -- should have role 1 
    AND RU2.user_id IS NULL  -- should NOT have role 2 
    AND RU3.user_id IS NULL  -- should NOT have role 3 
    AND RU4.user_id IS NOT NULL -- should have role 4 

where句で「IS NULL」と「IS NOT NULL」を変更するだけで、ユーザーに必要なロールを変更することができます。

1

group_concatあなたが望むものである:

select 
    case roles 
     when '1' then 'members' 
     when '1,2' then 'admins' 
     when '1,2,3' then 'sellers' 
     when '1,4' then 'partners' 
     else 'uh??' 
    end role, 
    count(user_id) nr_users from (
     select user_id, group_concat(role_id order by role_id separator ',') roles 
     from roles_users 
     group by user_id 
    ) 
group by role 
order by role; 

ところで、あなたはビットマスクを使用して、より効率的な役割を格納することができます。利点:ユーザーIDごとに1つの列のみ。欠点:クエリを作成するのが難しい...

+0

私はこれが好きです。しかし、返される文字列が常に同じであることを保証するために、内側のクエリでrole_idによる注文が必要ですか(つまり、 '1,2,3'ではなく '3,1,2')? – Glenn

+0

グループ化される前に順序付けされているのは、group_concatステートメント自体にあります。 – fge

+0

申し訳ありませんが、それをキャッチしませんでした。それは素晴らしい解決策です。私はOracleにそのような機能があったらいいと思う。 – Glenn

0

最もエレガントされないが、スタート

SELECT user_id 
     ,CASE WHEN (role1 > 0 AND 0 = role2 AND 0 = role3 AND 0 = role4) THEN 'MEMBER' 
     WHEN (role1 > 0 AND role2 > 0 AND 0 = role3 AND 0 = role4) THEN 'ADMIN' 
     WHEN (role1 > 0 AND role2 > 0 AND role3 > 0 AND 0 = role4) THEN 'SELLER' 
     WHEN (role1 > 0 AND 0 = role2 AND 0 = role3 AND role4 > 0) THEN 'PARTNER' 
     ELSE 'Something else' 
     END AS type 
    FROM (
    SELECT user_id 
      ,SUM(CASE role_id WHEN 1 THEN 1 ELSE 0 END) AS role1 
      ,SUM(CASE role_id WHEN 2 THEN 1 ELSE 0 END) AS role2 
      ,SUM(CASE role_id WHEN 3 THEN 1 ELSE 0 END) AS role3 
      ,SUM(CASE role_id WHEN 4 THEN 1 ELSE 0 END) AS role4 
     FROM roles_users 
     GROUP BY user_id 
    ) x 

編集:私は、これは間違った質問に答えるされて推測、それは各ユーザーの種類を示しています。

0

ここではINTERSECTとMINUSを使用したソリューションです。悲しいことに、これらはまだMySQLではサポートされていませんが、誰かがこの有用性に気付くかもしれません。

- 役割1

SELECT user_id FROM 
(SELECT user_id, role_id FROM roles_users WHERE role_id = 1) 
MINUS SELECT user_id FROM roles_users WHERE role_id NOT IN (1) 

でユーザを見つける - ロール1及び2

SELECT user_id FROM 
(SELECT user_id, role_id FROM roles_users WHERE role_id = 1 
    INTERSECT SELECT user_id, role_id FROM roles_users WHERE role_id = 2) 
MINUS SELECT user_id FROM roles_users WHERE role_id NOT IN (1,2) 

持つユーザーを探す - ロール1,2とのユーザーの検索、3

SELECT user_id FROM 
(SELECT user_id, role_id FROM roles_users WHERE role_id = 1 
    INTERSECT SELECT user_id, role_id FROM roles_users WHERE role_id = 2 
    INTERSECT SELECT user_id, role_id FROM roles_users WHERE role_id = 3) 
MINUS SELECT user_id FROM roles_users WHERE role_id NOT IN (1,2,3) 

から4

、ロールの1を持つユーザーを探します