sql - 如何正确构造此 sql 查询?

标签 sql postgresql relational-database

我有五个表:

用户

 user_id | name
--------------------
    0    | Mark  
    1    | Jen
    2    | Mbali
    3    | Mbabani
    4    | Fang Zhao

作用

 role_id | name
--------------------
    3    | Employee
    4    | Customer Asia
    5    | Customer Africa

User_Role_Assoc

 role_id | user_id
--------------------
    3    |   0
    3    |   1
    3    |   2
    5    |   3
    4    |   4

Role_Reps

 role_id | user_id
--------------------
    4    |   0
    4    |   1

请求

 req_id  | user_id
--------------------
    8    |   3
    9    |   3
   10    |   4
   11    |   4

Mark、Jen 和 Mbali 都是一家虚构公司的员工 (role_id=3)。另外两个用户 Mbabani 和方召是创建请求的客户。

查询应该能够看到 req_id 8 和 9 是由属于 Customer Africa 角色(通过 User_Role_Assoc)的用户 (Mbabani[3]) 请求的,该角色没有分配代表 (Role_Reps)。

查询应该能够看到 req_id 10 和 11 是由属于 Customer Asia 角色(通过 User_Role_Assoc)的用户(Fang Zhao[4])请求的,该角色确实有代表。

所有员工都应该能够看到所有请求。除非在 Role_Reps 表中为该角色分配了角色代表。如果有任何代表,在本例中为 Mark 和 Jen,则他们是唯一有权查看请求的人。如果 Role_Reps 表中没有定义任何代表,那么每个人都应该能够看到请求。

所以我需要一个查询:

如果我传入 userid=2 (Mbali),我应该得到以下结果:

 req_id  | user_id
--------------------
   10    |   4
   11    |   4

如果我传入 userid=0userid=1(Mark 或 Jen),我应该得到以下结果:

 req_id  | user_id
--------------------
    8    |   3
    9    |   3
   10    |   4
   11    |   4

我希望我已经说清楚了。


更新

以下是使用数据生成表格的 DDL:

DROP TABLE IF EXISTS t_user;


CREATE TABLE t_user (
    userid          integer PRIMARY KEY,
    name            varchar(20)
);

GRANT ALL PRIVILEGES ON t_user TO PUBLIC;

INSERT INTO t_user (userid, name) VALUES (0,'Mark');
INSERT INTO t_user (userid, name) VALUES (1,'Jen');
INSERT INTO t_user (userid, name) VALUES (2,'Mbali');
INSERT INTO t_user (userid, name) VALUES (3,'Mbabani');
INSERT INTO t_user (userid, name) VALUES (4,'Fang Zhao');



DROP TABLE IF EXISTS t_role;


CREATE TABLE t_role (
    roleid          integer PRIMARY KEY,
    name            varchar(20)
);

GRANT ALL PRIVILEGES ON t_role TO PUBLIC;

INSERT INTO t_role (roleid, name) VALUES (3,'Employee');
INSERT INTO t_role (roleid, name) VALUES (4,'Customer Asia');
INSERT INTO t_role (roleid, name) VALUES (5,'Customer Africa');


DROP TABLE IF EXISTS t_user_role_assoc;


CREATE TABLE t_user_role_assoc (
    roleid          integer,
    userid          integer,
    primary key(roleid, userid)
);

GRANT ALL PRIVILEGES ON t_user_role_assoc TO PUBLIC;

INSERT INTO t_user_role_assoc (roleid, userid) VALUES (3,0);
INSERT INTO t_user_role_assoc (roleid, userid) VALUES (3,1);
INSERT INTO t_user_role_assoc (roleid, userid) VALUES (3,2);
INSERT INTO t_user_role_assoc (roleid, userid) VALUES (5,3);
INSERT INTO t_user_role_assoc (roleid, userid) VALUES (4,4);




DROP TABLE IF EXISTS t_role_reps;


CREATE TABLE t_role_reps (
    roleid          integer,
    userid          integer,
    primary key(roleid, userid)
);

GRANT ALL PRIVILEGES ON t_role_reps TO PUBLIC;

INSERT INTO t_role_reps (roleid, userid) VALUES (4,0);
INSERT INTO t_role_reps (roleid, userid) VALUES (4,1);


DROP TABLE IF EXISTS t_request;


CREATE TABLE t_request (
    req_id          integer PRIMARY KEY,
    userid          integer
);

GRANT ALL PRIVILEGES ON t_request TO PUBLIC;

INSERT INTO t_request (req_id, userid) VALUES (8,3);
INSERT INTO t_request (req_id, userid) VALUES (9,3);
INSERT INTO t_request (req_id, userid) VALUES (10,4);
INSERT INTO t_request (req_id, userid) VALUES (11,4);

最佳答案

正如一般建议,我发现通过使用自然键而不是代理项建立一组新关系通常更容易了解发生了什么。所以在这种情况下,我可能会这样做:

User
-------------------------
 username    | name
-------------------------
  mark       | Mark  
  jen        | Jen
  mbali      | Mbali
  mbabani    | Mbabani
  fangzhao   | Fang Zhao

Role
------------------------------------
 role_id          | name
------------------------------------
  employee        | Employee
  customer_asia   | Customer Asia
  customer_africa | Customer Africa

User_Role_Assoc
------------------------------
 role_id          | user_id
------------------------------
  employee        | mark
  employee        | jen
  employee        | mbali
  customer_africa | mbabani
  customer_asia   | fangzhao

Role_Reps
----------------------------
 role_id          | user_id
----------------------------
  customer_asia   | mark
  customer_africa | jen

Request
---------------------
 req_id  | user_id
---------------------
  8      | mbabani
  9      | mbabani
 10      | fangzhao
 11      | fangzhao

现在,当您开始构建查询时,您不必一次完成所有连接,您可以交互式地添加一个又一个连接,并且随着您越来越接近您的需要,它对您来说会更加清晰。完成后,您可以将该查询直接带回您的实际数据库,其中包含所有内容的代理 ID,它将“正常工作”。

关于您的实际问题,您指望没有触发其他事物存在的事物。我通常发现这种东西很难用 SQL 表达。您可能会发现,如果您向其中一个关系添加额外数据以表示某些内容是公共(public)的或全局的,并执行受限查询 UNION 并使用单独的查询来获取所有全局内容,您可能会发现它更容易。 p>

关于sql - 如何正确构造此 sql 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9119470/

相关文章:

java - 高效的多SQL插入

sql - PostgreSQL 从选择中插入但忽略现有行

mysql - 当数据可以分为类别但都属于一个共同类别时,如何设计表格?

sql - SSIS错误代码描述长度

mysql - 在同一个表的表上插入行

mysql - 通过另一列对联合选择中的列进行排序

postgresql - 将没有时区的时间的默认值插入为 hh :mm:ss format in Postgres sql

django - 多家公司使用django系统,同一个项目的小贴士

Yii2如何检查两个模型是否已经链接

php - 三个表之间的关系 : proper query and design suggestion