web-dev-qa-db-ja.com

「ユーザーとグループ」と「グループ内のグループ」のテーブル設計

ユーザーとグループを表す必要があります。グループは他のグループ内にネストできます。

(私の設計の選択ではありません。私は別のシステムを複製しており、この動作を模倣する必要があります。その実装の詳細にアクセスすることはできず、ユーザードキュメントにのみアクセスします。)

グループを他のグループに入れると、階層が作成されます。別のグループに配置されたあるグループのユーザーは、両方のグループのアクセス権限を取得します。たとえば、ExecutivesグループをAccountingグループに配置すると、Executivesグループのユーザーは両方のグループの権限を享受できます。ただし、Accountingグループにのみ配置されたユーザーは、そのグループの特権のみを利用できます。 (確かに、ありそうな現実的なビジネスシナリオではなく、単なる不自然な例です。)

このようなもの ERD図 と思います。

enter image description here

私は 多対多の関係user_からgroup_の処理方法を知っています。しかし、私にはわかりません。

  • ネストされたグループ内グループを表す方法。グループは、0、1、または複数の他のグループに属することができます。
  • 「このグループXはグループYの中にあるか」を照会する方法。
  • 「このユーザーはグループXのボブですか?」を照会する方法。「グループXは、そのユーザーに直接割り当てられているか、group-within-groupを介して継承されている」。

このグループ内のグループは「再帰的な」関係と見なされますか?正しい専門用語は何ですか?

関連する可能性があります: SQL Serverの再帰クエリ および 特定する再帰SQLクエリ

3
Basil Bourque

自己参照キー(隣接リスト、階層関係、再帰的関係)に直行するだけです。「最も適切で適切な」用語が何であるかはわかりませんが、これらのいずれもポイントに到達する必要があります。メンバーシップテーブルとともに、「プリンシパル」または「ロール」テーブルとなるものについて十分にチューニングされたオーディエンス)。私はSQL Serverからインスピレーションを得ていますが、PostgreSQLも\duまたは\dgで示されているような独自のセキュリティ管理のためにこれを行います。とはいえ、組み込みのセキュリティ管理でこれをすべて処理しようとすることを検討することにも価値があるかもしれません。

CREATE ROLE accounting;
GRANT SELECT ON account TO accounting;
CREATE ROLE executives;
GRANT accounting TO executives;
CREATE USER cto_bill;
GRANT executives TO cto_bill;

「CTO Bill」は、SELECTテーブルから、accountロールを介してexecutivesロールまで、accountingから、すべて完全にボックス。アプリケーションがチェーン化された権限を知る必要がある場合、\duまたはpg_catalogpg_auth_membersおよびpg_rolesテーブルに対するクエリの形式を介して公開できます。

SELECT  r.rolname, r.rolsuper, r.rolinherit,
        r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,
        r.rolconnlimit, ARRAY(  SELECT  b.rolname
                                FROM    pg_catalog.pg_auth_members m
                                INNER JOIN pg_catalog.pg_roles b 
                                    ON  ( m.roleid = b.oid )
                                WHERE   m.member = r.oid ) as memberof
FROM    pg_catalog.pg_roles r
WHERE   r.rolcanlogin = 'f'
ORDER BY 1;

完全な解決策が必要であると思われる場合は、 this のようなスキーマを構築できます。

CREATE TABLE Principal
(
    Principal_PK             SERIAL NOT NULL,
    Name                     VARCHAR( 128 ) NOT NULL,
    PasswordHash             BYTEA,
    Type                     CHAR( 1 ) NOT NULL
);

ALTER TABLE Principal
ADD CONSTRAINT PK__Principal
    PRIMARY KEY ( Principal_PK );

ALTER TABLE Principal
ADD CONSTRAINT UQ__Principal__Name
    UNIQUE ( Name );

ALTER TABLE Principal
ADD CONSTRAINT CK__Principal__Type
    CHECK ( Type IN ( 'U', 'G' ) );

CREATE TABLE PrincipalMembership
(
    PrincipalMembership_PK   SERIAL NOT NULL,
    Principal_FK             INTEGER NOT NULL,
    IsMemberOfPrincipal_FK   INTEGER NOT NULL,
    DateCreated              TIMESTAMP NOT NULL
);

ALTER TABLE PrincipalMembership
ADD CONSTRAINT PK__PrincipalMembership
    PRIMARY KEY ( PrincipalMembership_PK );

ALTER TABLE PrincipalMembership
ADD CONSTRAINT FK__PrincipalMembership__Principal
    FOREIGN KEY ( Principal_FK )
    REFERENCES Principal ( Principal_PK );

ALTER TABLE PrincipalMembership
ADD CONSTRAINT FK__PrincipalMembership__IsMemberOfPrincipal
    FOREIGN KEY ( IsMemberOfPrincipal_FK )
    REFERENCES Principal ( Principal_PK );

ALTER TABLE PrincipalMembership
ADD CONSTRAINT UQ__PrincipalMembership__Principal__IsMemberOfPrincipal
    UNIQUE ( Principal_FK, IsMemberOfPrincipal_FK );

ALTER TABLE PrincipalMembership
ALTER COLUMN DateCreated SET DEFAULT ( NOW() );

INSERT  INTO Principal ( Name, PasswordHash, Type )
VALUES  ( 'accounting', NULL, 'G' ),
        ( 'executives', NULL, 'G' ),
        ( 'cto_bill', E'\\x00', 'U' );

INSERT  INTO PrincipalMembership ( Principal_FK, IsMemberOfPrincipal_FK )
SELECT  p.Principal_PK, m.Principal_PK
FROM (      SELECT  'executives', 'accounting'
UNION ALL   SELECT  'cto_bill', 'executives' ) pl ( Name, IsMemberOf )
INNER JOIN Principal p
    ON  p.Name = pl.Name
INNER JOIN Principal m
    ON  m.Name = pl.IsMemberOf;

次に、 Recursive CTE など、必要なほとんどすべてのツリー走査メソッドを使用して、さまざまなメンバーシッププロパティを決定します。

;WITH RECURSIVE cte_Membership AS (
    SELECT  p.Principal_PK, p.Name, pm.IsMemberOfPrincipal_FK
    FROM    Principal p
    LEFT JOIN PrincipalMembership pm
        ON  pm.Principal_FK = p.Principal_PK
    UNION ALL
    SELECT  c.Principal_PK, c.Name, pm.IsMemberOfPrincipal_FK
    FROM    cte_Membership c
    INNER JOIN Principal p
        ON  p.Principal_PK = c.IsMemberOfPrincipal_FK
    INNER JOIN PrincipalMembership pm
        ON  pm.Principal_FK = p.Principal_PK )
SELECT  m.Name, p.Name AS IsMemberOf
FROM    cte_Membership m
LEFT JOIN Principal p
    ON  p.Principal_PK = m.IsMemberOfPrincipal_FK
ORDER BY m.Name, IsMemberOf;

編集:自己参照キーと再帰トラバーサルを含むソリューションの管理は、注意が急がれないと急いで爆乳になる可能性があることを言及することはおそらく非常に価値があります循環参照が行われないようにするために取られました。 (誤って)accountingexecutivesグループのメンバーにすると、サンプルのCTEは機能しなくなり、階層の複雑さが増すため、そのようなエラーが発生する可能性が高くなります。率直に言って、循環参照からの保護は少しお尻の苦痛ですが、このような場合、ストアドプロシージャでこれらのテーブルに対してCRUD操作を非表示にすると非常に役立ちます。既存のソリューションを複製しようとしているので、そのシステムには、新しいソリューションに適したリトマステストの開発に役立つガイドラインがいくつかあります。

1
Avarkx

まず始めに-group_の自己関係は1対多ですかよろしいですかExecutivesAccountingのメンバーであるだけでなく、Penthouse Restaurantのメンバーでもあるように思えます。同様に、AccountingにはExecutivesだけでなく Trolls も含まれます。これは多対多であり、ユーザー/グループの相互作用に関する問題はすでに解決しています。ここでも同じように解決します。

1対多であることが確実である場合は、SQLに いくつかの異なる実装 のツリーがあります。

0
Michael Green