2012-02-02 54 views
0

我有五个表:如何正确构造这个sql查询?

用户

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 

马克,仁和姆巴利是一个虚构的公司的所有员工(ROLE_ID = 3)。另外两名用户Mbabani和Fang Zhao是创建请求的客户。

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

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

所有员工应该能够看到所有请求。除非在Role_Reps表中有角色代表被分配给该角色。如果有任何代表,在这种情况下,马克和仁,他们是唯一允许看到请求。如果在Role_Reps表中没有定义任何代表,那么每个人都应该能够看到这些请求。

所以我需要一个查询:

如果我传递一个userid=2(姆巴利)我应该得到以下结果:

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

如果我通过在userid=0userid=1(马克或仁)我应该得到以下结果:

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

我希望我已经说清楚了。


UPDATE

这里是的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); 

回答

2

正如一般性的建议,我觉得它往往更容易地看到发生了什么事情通过使一组新的使用自然键而不是替代者的关系。因此,在这种情况下,我可能做到这一点:当你去构建你的查询

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中很难表达。如果向其中一个关系添加其他数据以表示某些内容是公开或全局的,并且使用单独的查询编辑受限制的查询以获取所有全局内容,则可能会更容易。

+0

是的,睡了之后我意识到我会以错误的方式去做。 – capdragon 2012-02-03 14:06:30

0

我认为这应该得到你想要的

SELECT R.req_id, R.user_id 
FROM Request R 
    INNER JOIN User_Role_Assoc A ON A.user_id = R.user_id 
    LEFT JOIN Role_Reps L ON L.role_id = A.role_id 
WHERE L.user_id IS NULL OR L.user_id = @user_id 
+0

我得到相同的结果'REQ_ID 8和9' nomatter什么'@ user_id'是 – capdragon 2012-02-02 21:57:40

1

希望我理解它,但这应该让你开始和结束(如果我联合国derstand如果右)

select r.req_id, 
u1.name as requestingUser, 
rl.name as BelongsToRole, 
coalesce(r2.name, '') as RoleRep 

from request R 
join user u1 on r.user_id=u1.user_id 
join user_role_assoc ura on ura.user_id=u1.user_id 
join role rl on rl.role_id=ura.role_id 
left join role_Reps r1 on r1.role_id=rl.role_id 
left join users R2 on r2.user_id=rl.user_id 
+0

'rl.userid'不存在,'IsNull'不是有效postgressql – capdragon 2012-02-02 22:02:56

+0

IsNull()返回有问题的字段,或者,如果字段为空,则为空字符串...使用coalesce(r2.name,'' )改为AS RoleRep。更新了答案.. – Sparky 2012-02-02 22:16:42

+0

对不起,我尝试了你给我的不同组合,但我没有得到我需要的结果。 (+1)的努力,因为我相信它的工作原理是如何理解它的。但无论如何,我意识到丹尼尔有一点,我需要以不同的方式去做。不过谢谢。 – capdragon 2012-02-03 14:05:43

0

嗨,我试了一下MSSQL。

第一个选择语句向您提供分配的代表请求,第二个选择语句请求用户的请求,其中没有分配代表。它看起来并不优化我知道,但至少它工作。我试过了。

SELECT EMPLOYEE.USER_ID 
    ,EMPLOYEE.NAME AS EMPLOYEE_NAME 
    ,CUSTOMER.NAME AS ASSIGNED_CUSTOMER_NAME 
    ,ASSIGNED_REQUESTS.REQ_ID AS REQ_ID 
    FROM USR EMPLOYEE 
INNER JOIN USER_ROLE_ASSOC URA ON EMPLOYEE.USER_ID = URA.USER_ID AND URA.ROLE_ID = 3 
LEFT JOIN ROLE_REPS RR ON EMPLOYEE.USER_ID = RR.USER_ID 
LEFT JOIN USER_ROLE_ASSOC CUSTOMER_ROLE ON RR.ROLE_ID = CUSTOMER_ROLE.ROLE_ID 
LEFT JOIN USR CUSTOMER ON CUSTOMER_ROLE.USER_ID = CUSTOMER.USER_ID 
LEFT JOIN REQUEST ASSIGNED_REQUESTS ON CUSTOMER.USER_ID = ASSIGNED_REQUESTS.USER_ID 
WHERE ASSIGNED_REQUESTS.REQ_ID IS NOT NULL 
UNION 
SELECT EMPLOYEE.USER_ID 
    ,EMPLOYEE.NAME AS EMPLOYEE_NAME 
    ,CUSTOMER.NAME AS ASSIGNED_CUSTOMER_NAME 
    ,ASSIGNED_REQUESTS.REQ_ID AS REQ_ID 
    FROM USR EMPLOYEE 
INNER JOIN USER_ROLE_ASSOC URA ON EMPLOYEE.USER_ID = URA.USER_ID AND URA.ROLE_ID = 3 
LEFT JOIN ROLE R ON R.ROLE_ID NOT IN (SELECT ROLE_ID FROM ROLE_REPS) AND R.ROLE_ID <> 3 
LEFT JOIN USER_ROLE_ASSOC CUSTOMER_ROLE ON R.ROLE_ID = CUSTOMER_ROLE.ROLE_ID 
LEFT JOIN USR CUSTOMER ON CUSTOMER_ROLE.USER_ID = CUSTOMER.USER_ID 
LEFT JOIN REQUEST ASSIGNED_REQUESTS ON CUSTOMER.USER_ID = ASSIGNED_REQUESTS.USER_ID 
WHERE ASSIGNED_REQUESTS.REQ_ID IS NOT NULL 

如果你只是想一个员工的要求,只是增加双方的where子句中进行选择:

And Employee.User_Id = ?