0

ユーザーの権限を選択して追加するSQLクエリがありますtrue

SELECT
    PrivilageName,
    'true' hasrights  <-- imaginary column
FROM
    users
NATURAL JOIN usermemberships
NATURAL JOIN groupprivileges
NATURAL JOIN `privileges`
WHERE
    UserID = '2'

結果は

AddBuilding           true
RemoveBuilding        true
EditBuilding          true

残りの特権に価値を加えようとしていfalseます。

AddBuilding           true
RemoveBuilding        true
EditBuilding          true
RemoveUser            false
AddUser               false

どうすればいいですか?

編集:テーブルの構造:

users(UserID)、、、、
usermemberships(UserID, groupID)_
groupprivileges(GroupID, PrivilegeID)_
privileges(PrivilegeID, PrivilageName)

編集:スペルミス、ごめんなさい。

4

2 に答える 2

1

(注:この回答のクエリが更新され、質問に追加された列名が含まれるようになりました。)

その結果セットを取得するための1つのアプローチは、すべての操作の代わりに、LEFT JOIN操作(caluseに適切な述語を含む)を使用することです。ONNATURAL JOIN

(私は、によって参照される列名を推測しているだけですNATURAL JOIN。それを解読するには、各テーブル定義を調べてすべての列のリストを取得し、一致するすべての列名を見つけて、図を作成する必要があります。 MySQLがこれらの内部結合操作を実行するために使用している列を調べます。)

クエリテキストで提供されたわずかな情報に基づいて、これが私が取るアプローチです(ここでも、各ON句で参照されている名前を推測するだけです)。

SELECT p.PrivilageName
     , IF(u.UserID IS NOT NULL,'true','false') AS hasrights
  FROM `privileges` p
  LEFT
  JOIN groupprivileges g 
    ON g.PrivilegeID = p.PrivilegeID
  LEFT
  JOIN usermemberships m
    ON m.GroupId = g.GroupID
  LEFT
  JOIN users u
    ON u.UserID = g.UserID
   AND u.UserID = 2

これらのテーブルのカーディナリティに応じて(つまり、ユーザーがメンバーであるグループとメンバーではないグループの2つの異なるグループに付与される「AddBuilding」特権です...)

また、「重複」PrivilageName値(「true」または「false」の複数の行、または各PrivilageNameの「true」と「false」の両方の行)を返さないようにするかどうか、および必要な方法に応じて結果セットが注文されました(つまり、すべての「真の」特権を最初にリストしますか?)...

次に、このクエリは返される結果セットでより決定論的であり、各PrivilageNameを1回だけ返します。この結果セットは、ユーザーが特権を持っているかどうかという質問に答えるのに適しているようです。

SELECT p.PrivilageName
     , MAX(IF(u.UserID IS NOT NULL,'true','false')) AS hasrights
  FROM `privileges` p
  LEFT
  JOIN groupprivileges g 
    ON g.PrivilegeID = p.PrivilegeID
  LEFT
  JOIN usermemberships m
    ON m.GroupId = g.GroupID
  LEFT
  JOIN users u
    ON u.UserID = g.UserID
   AND u.UserID = 2
 GROUP BY p.PrivilageName
 ORDER BY hasrights DESC, p.PrivilageName ASC

(個人的には、ORDER BYを省略し、結果をPrivilageNameで並べ替えますが、ORDER BYを使用すると、質問で指定された結果セットとよりよく一致します。)


もちろん、これが結果セットを取得する唯一の方法ではありませんが、(適切なインデックスが与えられれば)最も効率的である可能性があります。

個人的には、私は使用しませんNATURAL JOIN。(ステートメント内の述語を確認したいのですが、誰かがクエリ内のテーブルの1つに一致する名前の列を追加した場合に、クエリが「壊れて」しまうことは望ましくありません。(実際、考えてみてください。通常、ほとんどすべてのテーブルの主キー列の名前であるため、NATURAL JOINを使用できませんid...外部キー列には通常名前が付けられreferencedtable_idます。)ただし、NATURALJOINを使用できる方法で列に名前を付けたとしても、私は潜在的な欠点がどんな利点よりも重要であると思います。

ただし、以下のステートメントのようなものが機能する可能性があります。(私はこのような構文を使用した経験がないので「かもしれない」と言います...私はNATURAL JOINを使用することはなく、常に右結合よりも左結合を好みます。私の店の誰かがこれを持って来たら、上記のステートメントを提供しますが、指定された結果セットを返すためにaを使用できないという印象を残したくありませんNATURAL JOIN。指定された結果セットは、次のようなステートメントによって返される可能性があります。

SELECT
    PrivilageName,
    MAX(IF(UserID=2,'false','true')) AS hasrights
FROM
    users
NATURAL RIGHT JOIN usermemberships
NATURAL RIGHT JOIN groupprivileges
NATURAL RIGHT JOIN `privileges`
GROUP BY PrivilageName
于 2013-02-14T16:02:53.887 に答える
0

UNIONを使用して、2つのリクエストを「連結」することができます。

そして、演算子IF()があなたを助けることができるかもしれません。

于 2013-02-14T15:49:26.973 に答える