2012-02-02 30 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 = ?