[英]SQL Query Across Multiple Joined Tables
我有三個表:Resource,Timesheet,TimePeriod。 資源有很多Timesheets,Timesheet有一個TimePeriod。 這用於我們跟蹤員工時間表。 我想弄清楚如何找出本周每個人的時間表的狀態。 問題是,如果一個人沒有填寫時間表,那么時間表中就不會有條目。 所以他們的狀態應為NULL。
這就是數據庫的樣子:
Resource
id | Name
---+------------
1 | John Smith
2 | Jason Bourne
Timesheet
id | Status | Resource_Id |TimePeriod_Id
---+-----------+-------------------------------
1 | Submitted | 1 | 1
2 | Created | 1 | 2
3 | Submitted | 2 | 1
TimePeriod
id | Week
---+----------------
1 | 2013Week1
2 | 2013Week2
3 | 2013Week3
如果TimePeriod存儲在同一個表中,那么這不會是一個問題。 但由於它在一個單獨的表中,我認為我正在進行聯接的方式存在問題。 我無法弄清楚這項工作的查詢。
我試過這個:
SELECT res.id, res.name, ts.status
FROM Resource res
LEFT JOIN Timesheet ts ON ts.resource_id = res.id
LEFT JOIN TimePeriod tp ON ts.timeperiod_id = tp.id
WHERE tp.week = '2013Week2'
這顯然從結果中消除了Jason Bourne,因為他沒有時間表
我也試過這個:
SELECT res.id, res.name, ts.status
FROM Resource res
LEFT JOIN Timesheet ts ON ts.resource_id = res.id
LEFT JOIN TimePeriod tp ON ts.timeperiod_id = tp.id AND tp.week = '2013Week2'
這會返回額外的行和錯誤的數據。
期望的結果是:
id name status
1 John Smith Created
2 Jason Bourne NULL
我相信我可以通過UNION絆倒我的方式,但我覺得除此之外應該有辦法做到這一點。 如果有人有任何建議我會非常感激。 謝謝。
您需要將Timesheet和內部聯接的組合LEFT JOIN連接到TimePeriod
語法是
SELECT res.id, res.name, ts.status
FROM Resource res
LEFT JOIN (Timesheet ts
INNER JOIN TimePeriod tp
ON ts.timeperiod_id = tp.id AND tp.week = '2013Week2')
ON ts.resource_id = res.id
您可能還希望執行COALESCE(ts.status, 'unsubmitted') status
來轉換空值
另一個:
SELECT r.id, r.Name, s.Status
FROM Resource r
INNER JOIN TimePeriod p ON p.week = '2013week2'
LEFT JOIN Timesheet s ON s.Resource_id = r.id AND s.TimePeriod_id = p.id
;
或者你可以用CROSS JOIN ... WHERE
替換INNER JOIN ... ON
CROSS JOIN ... WHERE
:
SELECT r.id, r.Name, s.Status
FROM Resource r
CROSS JOIN TimePeriod p
LEFT JOIN Timesheet s ON s.Resource_id = r.id AND s.TimePeriod_id = p.id
WHERE p.week = '2013week2'
;
雖然必須說MySQL不區分CROSS JOIN
和INNER JOIN
,但將它們視為彼此的同義詞。 無論如何,上面的查詢是標准的SQL,可以在任何SQL產品中使用。
SQL Fiddle上的SQL Server演示: http ://sqlfiddle.com/#!3 / 6a0a1 / 2
試試這個。
SELECT res.id, res.name, ts.status
FROM [Resource] res
INNER JOIN Timesheet ts ON ts.resource_id = res.id
LEFT JOIN TimePeriod tp ON ts.timeperiod_id = tp.id
WHERE tp.week = '2013Week2'
這當然不會在本地創建數據。 如果這不起作用,請告訴我,我會再次嘗試並在本地重新創建您的結構。
嘗試從資源表加入
SELECT res.id, res.name, ts.status
FROM Resource res
RIGHT JOIN Timesheet ts ON ts.resource_id = res.ID
LEFT JOIN TimePeriod tp on ts.timeperiod_id = tp.id AND tp.week - '2013Week2'
這樣,您應該為所有存在的資源獲取存在且不存在的時間表,並且只有給定時間段的時間表。
看起來像這樣。 參考下面發布的SQLfiddle。
select r1.id, r1.name, ts.status
from resource r1, resource r2, timesheet ts
where r1.id = r2.id (+)
and r2.id = ts.resource_id
and ts.timeperiod_id = (select max(id) from timeperiod)
編輯:使用更明確的連接語法:
SELECT r1.id, r1.name, ts.status
FROM resource r1
LEFT OUTER JOIN resource r2 ON r1.id = r2.id
JOIN timesheet ts ON r2.id = ts.resource_id
WHERE ts.timeperiod_id = :timeperiod -- you can use whatever timeperiod you want, doesn't have to be the max(id)
下面的代碼使用您在上面提供的數據創建三個本地臨時表。
許多人不知道交叉應用可以像完全外連接一樣使用。
因此,我們想要本周的資源條目和時間段條目的叉積。 無論有人提交了時間表。
下一步是從時間表中繼續加入資源ID和時間段的結果。 這將顯示已創建和已提交的條目。
這假設更新不會將創建的內容移動到提交的列。 添加另一個表,其中1 =已創建且2 =已提交並獲取最大值可列出前一個表。
結果如下所示。
John Miner,craftydba,www.craftydba.com
- 資源表
創建表#Resource
(res_id int,res_name varchar(128));
- 添加數據
插入#Resource
值
(1,'約翰史密斯'),
(2,'Jason Bourne');
- 時間段表
創建表#TimePeriod
(tp_id int,tp_week int);
- 添加數據
插入#TimePeriod
值
(1,201301),
(2,201302),
(3,201303);
- 時間表表
創建表#TimeSheet
(ts_id int,ts_status varchar(16),res_id int,tp_id int);
- 添加數據
插入#TimeSheet
值
(1,'已提交',1,1),
(2,'創建',1,2),
(3,'已提交',2,1);
- 無論時間段如何,都需要資源和期間
選擇 *
來自#Resource r
交叉申請
(從#TimePeriod p1中選擇*,其中p1.tp_week = 201302
)作為ca_Period
在s.res_id = r.res_id和ca_Period.tp_id = s.tp_id上左連接#TimeSheet
試試這個。 它會根據您的數據進行測試。 但是您不會獲得任何資源的NULL值。
SELECT Resource.id,Resource.Name,TimeSheet.Status FROM Resource,TimeSheet,TimePeriod WHERE Resource.id = TimeSheet.id AND TimeSheet.TimePeriod_id = TimePeriod.id AND TimePeriod.Week =“2013Week1”
希望能幫助到你。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.