數據庫作業有一道題是這樣子的:
有一張名叫emp的表記錄員工信息,其中有如下字段 HIREDATE 表示員工被雇用的日期:
然后問題是這樣的:
q7.Show details of employee hiredates and the date of their first payday.
(Paydays occur on the last Friday of each month)
(plus their names)
意思就是每個月的最后一個周五是發工資的日子,要我們輸出他們領到第一桶金的日子。(這里其實是計算當月payday,不考慮hiredate超過payday的情況)
那么怎么通過一個日期計算出當月的最后一個周五呢?我們用最暴力的方法,直接迭代計算:
思路:
LAST_DAY 函數找當月最后一天 x
日期 x 逐天減少
直到 x 等于周五,即是最后一個周五
代碼:
DELIMITER $$# 結束符由 ; 改為 $$ 。因為函數中間需要用到 ; 號
DROP FUNCTION IF EXISTS last_friday $$# 刪除之前定義的函數 last_friday
CREATE FUNCTION last_friday (dt DATE) RETURNS DATE# 定義函數 last_friday 有一個DATE類的形參 dt,返回DATE對象
BEGIN
DECLARE last DATE;# 臨時變量 last
SET last=LAST_DAY(dt);# last=dt的最后一天
WHILE DATE_FORMAT(last, "%W")!="Friday" DO# 不斷判斷是否為周五
SET last=DATE_SUB(last, interval 1 day);# 迭代減少天數
END WHILE;
RETURN last;# 返回結果
END $$
DELIMITER ;# 結束符由 $$ 改為 ; 號
# 不帶注釋 ↓
DELIMITER $$
DROP FUNCTION IF EXISTS last_friday $$
CREATE FUNCTION last_friday (dt DATE) RETURNS DATE
BEGIN
DECLARE last DATE;
SET last=LAST_DAY(dt);
WHILE DATE_FORMAT(last, "%W")!="Friday" DO
SET last=DATE_SUB(last, interval 1 day);
END WHILE;
RETURN last;
END $$
DELIMITER ;
然后我們就可以通過 last_friday 函數進行查詢:
SELECT ENAME, HIREDATE, last_friday(HIREDATE) FROM emp;
結果:
然后下一題:
q8.Refine your answer to 7 such that it works
even if an employee is hired after the last Friday of the month
(cf Martin)
意思是有一些員工是在payday之后入職的,比如:
那么我們應該找下一個payday。思路也很簡單,通過 if 語句進行判斷即可。
如果當月payday大于入職日期hiredate,返回當月payday
如果當月payday小于入職日期hiredate,返回下個月的payday
我們首先編寫一個函數next_friday,計算下個月的payday:
DELIMITER $$
DROP FUNCTION IF EXISTS next_friday $$
CREATE FUNCTION next_friday (dt DATE) RETURNS DATE
BEGIN
DECLARE last DATE;
SET last=LAST_DAY(DATE_ADD(dt, interval 1 month));
WHILE DATE_FORMAT(last, "%W")!="Friday" DO
SET last=DATE_SUB(last, interval 1 day);
END WHILE;
RETURN last;
END $$
DELIMITER ;
這個函數和 last_friday 沒啥區別,就是計算下個月而已:
隨后我們修改 last_friday ,最后返回時加一個判斷即可:
DELIMITER $$
DROP FUNCTION IF EXISTS last_friday $$
CREATE FUNCTION last_friday (dt DATE) RETURNS DATE
BEGIN
DECLARE last DATE;
SET last=LAST_DAY(dt);
WHILE DATE_FORMAT(last, "%W")!="Friday" DO
SET last=DATE_SUB(last, interval 1 day);
END WHILE;
RETURN IF(last>dt, last, next_friday(dt));
END $$
DELIMITER ;
注意這個 if 表達式即可:
if(expr, case1, case2)
if(條件, 情況1, 情況2)
隨后再次運行查詢:
舒服了