1

私はSQLの初心者で、この例に従おうとしています: http://net.tutsplus.com/tutorials/php/a-better-login-system/

問題の要点は、

  1. permissionsリソースへのアクセスを許可するものがあります
  2. roles複数持つことができるものがありますpermissions
  3. 複数と複数のusers可能性があるものがありますrolespermissions

db テーブルは次のようにリストされます。

permission role user role_permissions user_rolesuser_permissions

テーブルを作成するコードは次のとおりです。

CREATE TABLE "permission" (
    "id" SERIAL PRIMARY KEY,
    "permission_key" VARCHAR(32) NOT NULL UNIQUE,
    "permission_name" VARCHAR(32) NOT NULL);

CREATE TABLE "role" (
    "id" SERIAL PRIMARY KEY,
    "role_name" varchar(32) NOT NULL);

CREATE TABLE "role_permissions" (
    "id" SERIAL PRIMARY KEY,
    "role_id" INTEGER NOT NULL,
    "permission_id" INTEGER  NOT NULL,
    "value"  BOOLEAN NOT NULL DEFAULT FALSE,
    "created_date" DATE NOT NULL, 
    UNIQUE ("role_id","permission_id"));

CREATE TABLE "user" (
    "id" SERIAL PRIMARY KEY,
    "username" VARCHAR(32) UNIQUE);

CREATE TABLE "user_permissions" (
    "id" SERIAL PRIMARY KEY,
    "user_id" INTEGER NOT NULL,
    "permission_id" INTEGER  NOT NULL,
    "value"  BOOLEAN NOT NULL DEFAULT FALSE,
    "created_date" DATE NOT NULL, 
    UNIQUE ("user_id","permission_id"));

CREATE TABLE "user_roles" (
    "id" SERIAL PRIMARY KEY,
    "user_id" INTEGER NOT NULL,
    "role_id" INTEGER NOT NULL,
    "created_date" DATE NOT NULL, 
    UNIQUE ("user_id", "role_id"));

私の質問は:

SQL文で次のように書けるようになりたいです。

  1. "その人がPERMISSIONS利用できるものをすべて見つけて"ROLENAME________

  2. "その人がPERMISSIONS利用できるものをすべて見つけて"USERNAME________

ID を使用してすべてに一致させることができることはわかっていますが、代わりに名前を使用したいと考えています。「ユーザー x のすべてのアクセス許可を見つけてください」と考える方が理にかなっているからです。

また、2 番目の質問では、ユーザーは次の 2 つの方法でアクセス許可を取得できることに注意してください。

User > Role > Permission
User > Permission   

簡潔にするために、単一のステートメントで結果を取得したいと思います。

また、誰かがそれをKormaクエリに変換する方法を知っていれば、とても感謝しています。

4

1 に答える 1

1

私はいくつかの選択をしなければなりませんでした。ユーザー権限とロール権限の両方がある場合は、ユーザー権限が適用されます。ユーザーとロールを zuser と zrole に置き換えました。これらは postgres の予約語であり、引用するのが好きではないためです。クエリは、現在の形式ではあまり美的ではありませんが、機能しているようです。データは架空のものです。

DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path='tmp';


CREATE TABLE permission
    ( id SERIAL PRIMARY KEY
    , permission_key VARCHAR(32) NOT NULL UNIQUE
    , permission_name VARCHAR(32) NOT NULL
    );
INSERT INTO permission(id,permission_key, permission_name) VALUES
 (1, 'Eat', 'Eat' ) , (2, 'Drink', 'Drink' )
 ,(3, 'Shit', 'Shit' ) , (4, 'Urinate', 'Urinate' )
    ;

CREATE TABLE zrole
    ( id SERIAL PRIMARY KEY
    , role_name varchar(32) NOT NULL
    );
INSERT INTO zrole(id, role_name) VALUES
  (1, 'Manager'), (2, 'Employee'), (3, 'Client') , (4, 'Visitor')
    ;

CREATE TABLE zuser
    ( id SERIAL PRIMARY KEY
    , username VARCHAR(32) UNIQUE
    );
INSERT INTO zuser(id, username) VALUES
  (1, 'Jan Kees de Jager'), (2, 'Wildplasser'), (3, 'Joop') , (4, 'Mina')
    ;

CREATE TABLE role_permissions
    ( id SERIAL PRIMARY KEY
    , role_id INTEGER NOT NULL REFERENCES zrole(id)
    , permission_id INTEGER  NOT NULL REFERENCES permission(id)
    , created_date DATE NOT NULL
    , value  BOOLEAN NOT NULL DEFAULT FALSE
    , UNIQUE (role_id,permission_id)
    );
INSERT INTO role_permissions( id, role_id, permission_id, created_date, value) VALUES
 (1,1,1, '2012-01-01', True )
,(2,1,2, '2012-01-01', False )
,(3,2,2, '2012-01-01', True )
,(4,2,3, '2012-01-01', False )
,(5,2,4, '2012-01-01', True )
,(6,3,2, '2012-01-01', True )
,(7,3,3, '2012-01-01', True )
,(8,3,4, '2012-01-01', True )
,(9,4,2, '2012-01-01', True )
,(10,4,3, '2012-01-01', True )
,(11,4,4, '2012-01-01', True )
    ;
CREATE TABLE user_permissions
    ( id SERIAL PRIMARY KEY
    , user_id INTEGER NOT NULL REFERENCES zuser(id)
    , permission_id INTEGER  NOT NULL REFERENCES permission(id)
    , created_date DATE NOT NULL
    , value  BOOLEAN NOT NULL DEFAULT FALSE
    , UNIQUE (user_id,permission_id)
    );

INSERT INTO user_permissions( id, user_id, permission_id, created_date, value) VALUES
 (1,1,1, '2012-01-01', False )
,(2,1,2, '2012-01-01', False )
,(3,2,2, '2012-01-01', True )
,(4,3,2, '2012-01-01', True )
,(5,4,1, '2012-01-01', True )
    ;

CREATE TABLE user_roles
    ( id SERIAL PRIMARY KEY
    , user_id INTEGER NOT NULL REFERENCES zuser(id)
    , role_id INTEGER NOT NULL REFERENCES zrole(id)
    , created_date DATE NOT NULL
    , UNIQUE (user_id, role_id)
    );

INSERT INTO user_roles (id, user_id, role_id, created_date) VALUES
 (1,1,1, '2010-01-01' )
,(2,2,2, '2010-01-01' )
,(3,3,4, '2010-01-01' )
,(4,4,3, '2010-01-01' )
-- uncomment the next line to add a duplicate role
-- ,(5,2,4, '2010-01-01' )

    ;

WITH lutser AS (
    SELECT up.user_id AS user_id
    , up.permission_id AS permission_id
    , up.value AS uval
    FROM user_permissions up
    )
, roler AS (
    SELECT
    ur.user_id AS user_id
    , rp.permission_id AS permission_id
    , rp.value AS rval
    FROM user_roles ur
    JOIN role_permissions rp ON rp.role_id = ur.role_id
    )
SELECT us.username
    , pe.permission_name
    , pe.id AS permission_id
    , lu.uval AS uval
    , ro.rval AS rval
    , COALESCE(lu.uval , ro.rval) AS tval
FROM lutser lu
FULL JOIN roler ro ON ro.user_id = lu.user_id
        AND ro.permission_id = lu.permission_id
JOIN zuser us ON us.id = COALESCE(lu.user_id ,ro.user_id)
JOIN permission pe ON pe.id = COALESCE(ro.permission_id , lu.permission_id)
    ;

結果:

     username      | permission_name | permission_id | uval | rval | tval 
-------------------+-----------------+---------------+------+------+------
 Jan Kees de Jager | Eat             |             1 | f    | t    | f
 Jan Kees de Jager | Drink           |             2 | f    | f    | f
 Wildplasser       | Drink           |             2 | t    | t    | t
 Wildplasser       | Shit            |             3 |      | f    | f
 Wildplasser       | Urinate         |             4 |      | t    | t
 Joop              | Drink           |             2 | t    | t    | t
 Joop              | Shit            |             3 |      | t    | t
 Joop              | Urinate         |             4 |      | t    | t
 Mina              | Eat             |             1 | t    |      | t
 Mina              | Drink           |             2 |      | t    | t
 Mina              | Shit            |             3 |      | t    | t
 Mina              | Urinate         |             4 |      | t    | t
(12 rows)

ところで: 上記のクエリはまだ正しくありません。ユーザーが複数のロールに属している場合、クエリはそのユーザーに対して複数の行を生成します。ロール サブクエリには、distinct/max() を追加する必要があります。

更新: 1 人あたりの役割の重複の問題を解決するために、この二重にネストされた CTE を作成しました。

WITH lutser AS (
    WITH aggr AS (
        WITH rope AS (
            SELECT DISTINCT
            ur.user_id AS user_id
            , rp.permission_id AS permission_id
            , rp.value AS value
            FROM user_roles ur
            JOIN role_permissions rp ON rp.role_id = ur.role_id
            GROUP BY ur.user_id , rp.permission_id , rp.value
            )
        SELECT user_id,permission_id, value
        FROM rope yes
        WHERE yes.value = True
        UNION ALL
        SELECT user_id,permission_id, value
        FROM rope nono
        WHERE nono.value = False
        AND NOT EXISTS (SELECT * FROM rope nx
                WHERE nx.user_id= nono.user_id
                AND nx.permission_id= nono.permission_id
                AND nx.value = True
                )
        )
    SELECT COALESCE(up.user_id , ag.user_id) AS user_id
    , COALESCE(up.permission_id , ag.permission_id) AS permission_id
    , up.value AS uval
    , ag.value AS rval
    FROM user_permissions up
    FULL JOIN aggr ag ON ag.user_id = up.user_id AND ag.permission_id = up.permission_id
    )
SELECT us.username
    , pe.permission_name
    , lu.uval AS uval
    , lu.rval AS rval
    , COALESCE(lu.uval , lu.rval) AS tval
FROM lutser lu
JOIN zuser us ON us.id = lu.user_id
JOIN permission pe ON pe.id = lu.permission_id
    ;

その機能は、データ行,(5,2,4, '2010-01-01' )を user_role テーブルに追加/コメント解除することで表示できます。ここでも、選択を迫られました。1 人のユーザーに 2 つの役割が存在し、真理値が競合する場合は、どちらかが優先されますTrue。クエリは簡素化/美化できると思いますが、少なくとも現在は正しく機能しています。

于 2012-06-23T17:13:28.287 に答える