簡體   English   中英

跨多個連接表的SQL查詢

[英]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來轉換空值

SQL小提琴

另一個:

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 JOININNER 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)

Sqlfiddle: http ://www.sqlfiddle.com/#!4 / 9dd71 /3

下面的代碼使用您在上面提供的數據創建三個本地臨時表。

許多人不知道交叉應用可以像完全外連接一樣使用。

因此,我們想要本周的資源條目和時間段條目的叉積。 無論有人提交了時間表。

下一步是從時間表中繼續加入資源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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM