寫在前面:我是「雲祁」,一枚熱愛技術、會寫詩的大數據開發猿。暱稱來源於王安石詩中一句
[ 雲之祁祁,或雨於淵 ]
,甚是喜歡。
寫博客一方面是對本身學習的一點點總結及記錄,另外一方面則是但願可以幫助更多對大數據感興趣的朋友。若是你也對數據中臺、數據建模、數據分析以及Flink/Spark/Hadoop/數倉開發
感興趣,能夠關注個人動態 ,讓咱們一塊兒挖掘大數據的價值~
天天都要進步一點點,生命不是要超越別人,而是要超越本身! (ง •_•)ง
面試
師兄在面試時遇到了這條SQL題,回來我幫他參謀了下,以爲很是有意思,讓咱們一塊兒來看看這道差點吊打師兄的筆試題吧!🤒sql
對方給了兩張表(分別是:派工記錄表和打卡記錄表),以及一張需求表(須要咱們寫查詢語句得出),內容以下:數據庫
一、表示某人從某日開始到某日結束,按要求工做,派工期間每日打卡時間必須在「要求到崗時間」前(含要求時間,精確到分鐘),不然遲到。函數
例如:oop
要求7:00,則6:59或者7:00:59 都不算遲到;7:01則視爲遲到1分鐘學習
二、行1中「派工結束日期」爲null,表示此人的工做結束時間還沒有肯定,還在搬磚中;
行2中派工結束日期爲2020-02-15,表示派工於02-15日結束。大數據
三、假設員工名字不重複,每人只有一條派工信息3d
建表語句以下:code
create table work_plan ( worker_name varchar(10), --人員 start_date date, --派工起始日 end_date date, --派工截止日 sign_time varchar(10) --派工期間的須要打卡時間 ) insert into work_plan values ('張三','2020-01-01',null,'06:30'), ('李四','2020-02-01','2020-02-15','07:00'), ('王五','2019-12-29','2020-03-30','06:00'), ('趙六','2019-12-29','2020-03-30','06:00')
在員工每次按指紋考勤時
都會生成一條記錄orm
建表語句以下:
create table sign_log ( worker_name varchar(10), sign_time datetime ) insert into sign_log values ('張三','2020-02-16 04:01'), ('張三','2020-02-16 05:02'), ('張三','2020-02-16 06:03'), ('王五','2020-02-16 07:03'), ('王五','2020-02-16 08:03'), ('王五','2020-02-16 09:03')
寫一個查詢語句,輸入參數:日期(date),輸出表格以下:
注:
一、2020-02-16李四派工期已結束,不在派工期間不須要計算考勤,故不用顯示
二、趙六在當日沒有打卡,按照遲到算,遲到時間1440分鐘
咱們要最終獲得遲到時間,須要用表二中最先的打卡時間減去表一中要求的截至打卡時間,但很明顯兩個表日期的數據格式不一致,對錶一的時間數據 sing_time 咱們須要和年份進行拼接,而後再與表二的打卡時間進行比較,便可得出最終咱們須要的遲到時間。😑
但在實際寫查詢語句時,我發現那樣會過於繁瑣,變考慮將上述步驟經過 SQL 中自定義函數來實現。先來複習下MySQL中的自定義函數。
自定義函數實例:
先來一個簡單的,建立一個函數將'2009-06-23 00:00:00'
這樣格式的datetime時間轉化爲'2009年6月23日0時0分0秒'
這樣的格式:
DELIMITER $$ DROP FUNCTION IF EXISTS `sp_test`.`getdate`$$ CREATE FUNCTION `sp_test`.`getdate`(gdate datetime) RETURNS varchar(255) BEGIN DECLARE x VARCHAR(255) DEFAULT ''; SET x= date_format(gdate,'%Y年%m月%d日%h時%i分%s秒'); RETURN x; END $$ DELIMITER ;
解析:
第一句是定義一個結束標識符,由於MySQL默認是以分號做爲SQL語句的結束符的,而函數體內部要用到分號,因此會跟默認的SQL結束符發生衝突,因此須要先定義一個其餘的符號做爲SQL的結束符;
第二句是若是這個函數已經存在了,就刪除掉,sp_test是數據庫的名字,函數是跟數據庫相關聯的,getdate是函數的名字;
第三句是建立一個函數,()裏是參數的名字和類型,RETURNS 定義這個函數返回值的類型;
函數體必須放在BEGIN END之間;
DECLARE 是定義函數體的變量,這裏定義一個變量x,默認是空,而後SET給x變量賦值;
RETURN 是返回值,這裏把變量x返回,x的類型必須與第三句中定義的返回類型一致。
調用:
SELECT getdate('2009-06-23 00:00:00');
返回 '2009年06月23日00時00分00秒'
咱們先來完成時間處理的自定義函數,代碼以下:
DELIMITER $$ DROP FUNCTION IF EXISTS func_date_sub $$ -- d1 6:00 d2 '2020-2-16 4:5:0' CREATE FUNCTION func_date_sub(d1 VARCHAR(20),d2 DATETIME) RETURNS INT BEGIN IF d2 IS NULL THEN RETURN -1440; ELSE RETURN CEIL((UNIX_TIMESTAMP(CONCAT('2020-2-16 ',d1))-UNIX_TIMESTAMP(d2))/60); END IF; END $$ DELIMITER ;
SQL 查詢語句以下:
select res.worker_name,res.attend,if(res.latetime<0,'是','否') as isLate,if( res.latetime<0,abs(res.latetime),0) as latetime from (select ck.worker_name,ck.attend,func_date_sub(ck.sign_time,ck.st) latetime from (select e.worker_name,e.sign_time,'2020-02-16' as attend,k.st from (select * from work_plan where datediff(end_date,'2020-2-16')>0 or end_date is null) e left join (select worker_name,min(sign_time) st from sign_log group by worker_name) k on e.worker_name = k.worker_name) ck)res;
最終結果仍是很是完美的,若是小夥伴有更好的意見,歡迎留言討論~