sql語句實現同一時間範圍內併發數統計計算

這是在做一個酒店系統時遇到的問題。通常情況下,一個服務生僅負責一個房間的客人用餐,但是,考慮到效益原因,酒店鼓勵服務生同時爲多個房間的客人提供服務。這樣,酒店每天要對在同一時間段內服務房間最多的一名服務生進行獎勵。表1列出了一天中酒店服務生所服務的房間號和服務時間。

 

服務清單

 

room_id

waiter_name

start_time

end_time

1

張嵐

2009-02-01 11:30:00.000

2009-02-01 13:30:00.000

2

張嵐

2009-02-01 11:40:00.000

2009-02-01 13:15:00.000

3

孫靜

2009-02-01 11:45:00.000

2009-02-01 14:20:00.000

4

孫靜

2009-02-01 11:39:00.000

2009-02-01 13:20:00.000

5

孫靜

2009-02-01 11:49:00.000

2009-02-01 14:16:00.000

6

孫靜

2009-02-01 10:37:00.000

2009-02-01 11:00:00.000

3

孫靜

2009-02-01 17:45:00.000

2009-02-01 18:20:00.000

4

孫靜

2009-02-01 17:39:00.000

2009-02-01 18:25:00.000

5

孫靜

2009-02-01 17:49:00.000

2009-02-01 18:36:00.000

6

孫靜

2009-02-01 17:37:00.000

2009-02-01 18:40:00.000

 

下面是建立服務清單數據的SQL語句。

 

CREATE TABLE Waiters

 

(

 

room_idint,

 

waiter_name char(20),

 

start_timedatetime,

 

end_timedatetime

 

);

 

INSERT INTO Waiters VALUES

 

(1,'張嵐','2009-02-01 11:30','2009-02-0113:30'),

 

(2,'張嵐','2009-02-01 11:40','2009-02-0113:15'),

 

(3,'孫靜','2009-02-01 11:45','2009-02-0114:20'),

 

(4,'孫靜','2009-02-01 11:39','2009-02-0113:20'),

 

(5,'孫靜','2009-02-01 11:49','2009-02-0114:16'),

 

(6,'孫靜','2009-02-01 10:37','2009-02-0111:00'),

 

(3,'孫靜','2009-02-01 17:45','2009-02-0118:20'),

 

(4,'孫靜','2009-02-01 17:39','2009-02-0118:25'),

 

(5,'孫靜','2009-02-01 17:49','2009-02-0118:36'),

 

(6,'孫靜','2009-02-01 17:37','2009-02-0118:40');

 

爲了更清楚地顯示出每名服務生在同一時間內所服務房間的數量,我們將服務清單中的數據以圖形的方式表示了出來。可以看出,雖然孫靜在中午和晚上都是服務了4個房間,但是隻有晚上4個房間的時間是重疊的。張嵐是2個房間的時間重疊在一起。這樣我們不難得出答案,在同一時間內張嵐最多的服務房間是2個,孫靜是4個。

 

 

服務清單數據圖形展示

 

1. 使用子查詢

 

要解決這個問題,首先要找出如何判斷時間重疊的方法。由圖1可以看出,當一個房間的服務開始之後,只要第二個房間的服務開始時間小於或等於第一個房間,並且結束時間大於第一個房間的開始時間的,就說明這兩個房間的服務時間存在重疊部分。例如,中午張嵐在1號房間的服務開始時間小於2號房間的開始時間,並且結束時間大於2號房間的開始時間,說明這兩個房間的服務時間重疊。而中午孫靜在5號房間的服務開始之後,6號、4號、3號的服務開始時間都小於5號,但是6號的服務結束時間小於5號的開始時間,說明6號與5號服務時間並不重疊。

 

按照上述邏輯,我們首先給出下面的查詢語句,以展示每個房間服務開始時所重疊的房間數量,查詢結果如表2所示。表中的黑體部分數據能夠更加明顯地說明出這種重疊,如4號與6號重疊,3號與46號重疊,5號則與346號重疊。

 

SELECT W1.waiter_name,

 

W1.start_time,

 

W1.end_time,

 

MAX(W1.room_id) AS room_id,

 

COUNT(*) AS tally

 

FROM Waiters AS W1

 

INNER JOINWaiters AS W2

 

ONW1.waiter_name = W2.waiter_name

 

ANDW2.start_time <= W1.start_time

 

ANDW2.end_time > W1.start_time

 

GROUP BY W1.waiter_name, W1.start_time,W1.end_time, W1.room_id

 

ORDER BY W1.waiter_name, W1.start_time, room_id;

 

房間重疊數量

 

waiter_name

start_time

end_time

room_id

tally

孫靜

2009-02-01 10:37:00.000

2009-02-01 11:00:00.000

6

1

孫靜

2009-02-01 11:39:00.000

2009-02-01 13:20:00.000

4

1

孫靜

2009-02-01 11:45:00.000

2009-02-01 14:20:00.000

3

2

孫靜

2009-02-01 11:49:00.000

2009-02-01 14:16:00.000

5

3

孫靜

2009-02-01 17:37:00.000

2009-02-01 18:40:00.000

6

1

孫靜

2009-02-01 17:39:00.000

2009-02-01 18:25:00.000

4

2

孫靜

2009-02-01 17:45:00.000

2009-02-01 18:20:00.000

3

3

孫靜

2009-02-01 17:49:00.000

2009-02-01 18:36:00.000

5

4

張嵐

2009-02-01 11:30:00.000

2009-02-01 13:30:00.000

1

1

張嵐

2009-02-01 11:40:00.000

2009-02-01 13:15:00.000

2

2

 

從上表可以看出,我們只要按服務生的姓名取出tally的最大值,就可以計算出每名服務生同時服務房間的最大數。下面是以子查詢方式給出的最終語句,查詢結果如表3所示。

 

SELECT T1.waiter_name, MAX(T1.tally) AS tally

 

FROM (SELECT W1.waiter_name,

 

W1.start_time,

 

W1.end_time,

 

COUNT(*) AS tally

 

FROMWaiters AS W1

 

INNER JOIN Waiters AS W2

 

ONW1.waiter_name = W2.waiter_name

 

AND W2.start_time <= W1.start_time

 

AND W2.end_time > W1.start_time

 

GROUPBY W1.waiter_name, W1.start_time, W1.end_time) AS T1

 

GROUP BY T1.waiter_name;

 

最終查詢結果

 

waiter_name

tally

孫靜

4

張嵐

2

 

2. 使用CTE

 

上面使用子查詢的方式得出了最終結果,這裏的子查詢實際上起到的是一種臨時結果集作用。所以,這個問題也可以使用CTE的方式進行查詢。

 

WITH T1 (waiter_name, start_time, end_time,tally) -- 定義CTE表達式的名稱和列

 

AS

 

(

 

SELECTW1.waiter_name,

 

W1.start_time,

 

W1.end_time,

 

COUNT(*) AS tally

 

FROMWaiters AS W1

 

INNERJOIN Waiters AS W2

 

ONW1.waiter_name = W2.waiter_name

 

ANDW2.start_time <= W1.start_time

 

ANDW2.end_time > W1.start_time

 

GROUP BYW1.waiter_name, W1.start_time, W1.end_time

 

)

 

SELECT waiter_name, MAX(tally) AS tally

 

FROM T1

 

GROUP BY T1.waiter_name; 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章