7

興味深い問題がありますが、複数の列を返す必要があるサブクエリがあると言うよりも、それを明確に表現する方法がよくわかりません。これを行おうとするとPostgreSQLがエラーをスローするので、SQLは論理的にはある程度健全に見えますが、明らかにこれを行うためのより良い方法があります。ユーザー権限を1つのテーブルにマージしようとしています(これをビューまたはある種の「マテリアライズドビュー」にスローすることを望んでいます)。これが私のテーブルです:

CREATE TABLE users (
  user_id integer NOT NULL,
  username character varying(32) NOT NULL,
  passwd character varying(32) NOT NULL,
  dept_id integer NOT NULL,
  last_activity timestamp with time zone NOT NULL DEFAULT now(),
  CONSTRAINT "pk-users-user_id" PRIMARY KEY (user_id)
);

CREATE TABLE groups (
  group_id integer NOT NULL,
  group_name character varying(32) NOT NULL,
  add_posts integer NOT NULL DEFAULT 0,
  remove_posts integer NOT NULL DEFAULT 0,
  modify_users integer NOT NULL DEFAULT 0,
  add_users integer NOT NULL DEFAULT 0,
  delete_users integer NOT NULL DEFAULT 0,
  CONSTRAINT "pk-groups-group_id" PRIMARY KEY (group_id)
);

CREATE TABLE user_groups (
  user_id integer NOT NULL,
  group_id integer NOT NULL,
  CONSTRAINT "fk-user_groups-group_id" FOREIGN KEY (group_id)
      REFERENCES groups (group_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT "fk-user_groups-user_id" FOREIGN KEY (user_id)
      REFERENCES users (user_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
);

CREATE TABLE user_rights (
  user_id integer NOT NULL,
  add_posts integer NOT NULL DEFAULT 0,
  remove_posts integer NOT NULL DEFAULT 0,
  modify_users integer NOT NULL DEFAULT 0,
  add_users integer NOT NULL DEFAULT 0,
  delete_users integer NOT NULL DEFAULT 0,
  CONSTRAINT "fk-user_rights-user_id" FOREIGN KEY (user_id)
      REFERENCES users (user_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE
);

そしてそれらを投入するためのいくつかのデータ:

INSERT INTO users(user_id, username, passwd, dept_id) VALUES (1, 'nicole','123456',12);
INSERT INTO users(user_id, username, passwd, dept_id) VALUES (2, 'john','324634',11);
INSERT INTO users(user_id, username, passwd, dept_id) VALUES (3, 'susan','61236',14);
INSERT INTO users(user_id, username, passwd, dept_id) VALUES (4, 'mary','1213612',2);
INSERT INTO user_rights(user_id, add_posts, remove_posts, modify_users, add_users, delete_users) VALUES (1,0,0,1,1,1);
INSERT INTO user_rights(user_id, add_posts, remove_posts, modify_users, add_users, delete_users) VALUES (2,1,1,1,1,1);
INSERT INTO user_rights(user_id, add_posts, remove_posts, modify_users, add_users, delete_users) VALUES (3,0,0,0,0,0);
INSERT INTO user_rights(user_id, add_posts, remove_posts, modify_users, add_users, delete_users) VALUES (4,0,0,0,0,0);
INSERT INTO groups(group_id, group_name, add_posts, remove_posts, modify_users, add_users, delete_users) VALUES (1,'Poster',1,1,0,0,0);
INSERT INTO groups(group_id, group_name, add_posts, remove_posts, modify_users, add_users, delete_users) VALUES (2,'User Mgr',0,0,1,1,1);
INSERT INTO groups(group_id, group_name, add_posts, remove_posts, modify_users, add_users, delete_users) VALUES (3,'Admin',1,1,1,1,1);
INSERT INTO user_groups(user_id, group_id) VALUES (1,1);
INSERT INTO user_groups(user_id, group_id) VALUES (2,2);
INSERT INTO user_groups(user_id, group_id) VALUES (3,2);
INSERT INTO user_groups(user_id, group_id) VALUES (4,3);
INSERT INTO user_groups(user_id, group_id) VALUES (1,2);

私がやろうとしているのは、ユーザーが持つ可能性のある有効なアクセス許可を計算できるクエリを作成することです。ユーザーは(ご想像のとおり)'users'テーブルに保存されます。'groups'のグループ、ユーザーが割り当てられる可能性のあるグループはすべて'user_groups'にあります。最後に、各ユーザーは、グループのアクセス許可をオーバーライドする必要がある個別のアクセス許可を持つことができます。これらは「user_rights」に保存されます。

私はこのすべての情報のクエリを次のように引き出すことができます(そして、はい、これは醜いことを知っています):

select
  max(add_posts) as add_posts,
  max(remove_posts) as remove_posts,
  max(modify_users) as modify_users,
  max(add_users) as add_users,
  max(delete_users) as delete_users
from
(
select 
  max(add_posts) as add_posts,
  max(remove_posts) as remove_posts,
  max(modify_users) as modify_users,
  max(add_users) as add_users,
  max(delete_users) as delete_users
from
  groups
where
  group_id in (select group_id from user_groups where user_id = 3)
union all
select  
  max(add_posts) as add_posts,
  max(remove_posts) as remove_posts,
  max(modify_users) as modify_users,
  max(add_users) as add_users,
  max(delete_users) as delete_users
from 
  user_rights
where
  user_id = 3
) as combined_user_groups

上記のデータを考えると、WHERE句で指定したすべてのユーザーに有効な権限が与えられます。私がやりたいのは、ユーザーまたはグループのデータが変更されたときにのみ更新されるマテリアライズド・ビューを作成することですが、それ以外の場合は静的です。これは問題なく行う方法を知っています-私が遭遇している問題は、このビューを生成することです。私の考えは上記のクエリを使用することですが、「users」テーブルの各ユーザーに対してクエリを実行し、「user_id」列を作成します。したがって、私の「effective_permissions」テーブルは次のようになります。

user_id, add_posts, remove_posts, modify_users, add_users, delete_users
1        1          1             1             1          1
2        1          1             1             1          1
3        0          0             1             1          1

..等々。この結果にuser_idを追加して、複数の行を表示する方法がわかりません。私がやろうとしていることを誰かが理解できるように、十分な情報を提供できたと思います。テーブルのサイズがグループ化されると、最終的にこの方法はパフォーマンスの面でかなりコストがかかる可能性があることを認識しています。このソリューションは、この問題を軽減するために思いつくことができる最善のソリューションのようです。

提供されている例は、テスト目的でサンプルデータを再作成する場合に機能するはずです(同じ概念が適用される実際のテーブルよりもはるかに単純ですが、ローカルのpgサーバーで非常にすばやく再構築しました)。

4

1 に答える 1

2
select
  user_id
  max(add_posts) as add_posts,
  max(remove_posts) as remove_posts,
  max(modify_users) as modify_users,
  max(add_users) as add_users,
  max(delete_users) as delete_users
from
(
select 
  ug.user_id
  max(g.add_posts) as add_posts,
  max(g.remove_posts) as remove_posts,
  max(g.modify_users) as modify_users,
  max(g.add_users) as add_users,
  max(g.delete_users) as delete_users
from
  groups g
inner join
  users_groups ug
on g.group_id = ug.group_id
group by    
  ug.user_id
union
select
  user_id  
  max(add_posts) as add_posts,
  max(remove_posts) as remove_posts,
  max(modify_users) as modify_users,
  max(add_users) as add_users,
  max(delete_users) as delete_users
from 
  user_rights
group by
  user_id
) as combined_user_groups
group by
  user_id
于 2011-05-22T03:02:14.977 に答える