數據庫課程設計之工程薪資基本項目管理(由python操控)

數據庫課程設計(python操控)

------必做內容(工程薪資基本項目管理):

這裏推薦一個在線繪製ER圖的網站,點擊此處進入

前言(課設要求)

1、項目需求簡述

  • 每位職工可以參加幾個不同的工程,且每個工程有多名職工參與;
  • 每位職工有一個職位,且多名職工可能有相同的職位;
  • 職位決定小時工資率,相同的職位具有相同的小時工資率;
  • 工程的基本信息包括:工程號和工程名稱,工程所在地址,起始時間,結束時間;
  • 職工的相關信息包括:職工號、姓名(職位和酬金?);
  • 企業按職工在每一個工程中完成的工時,計算酬金。
  • 員工檔案管理 員工有新增、離開、部門變更
  • 其它業務:企業有不同的部門(部門編號及名稱)組成,每個員工隸屬於部門之一; 職工參加工程上班簽到和下班簽到

2、要求

  • 應用規範設計法設計該數據庫,要求達到3NF。請給出詳細設計過程(E-R及E-R到關係表清晰的轉換關係說明)。
  • 指出每個關係的主碼和外碼。
  • 設計一個存儲過程(函數),以工程編號作爲輸入參數,實現計算某工程所支付的工人酬金。沒有該工程返回-1
  • 實現員工變更部門的存儲過程,成功返回 1,否則返回0;變更過程計入檔案;職工號/變更類型/原先部分(新增null)/新的部門(離開null)/日期/經手人
  • 員工參加工程的上班和下班 存儲過程/函數(注意時間點 早上6:之前和晚上12點後 不允許操作,當天沒有上班的不允許下班的操作…)

3、成果形式

  • 文檔 E-R總體圖(實體名稱/聯繫屬性/聯繫類型),每個實體詳細的屬性及其候選碼屬性可以另行標註(實體圖或者實體名(x,x…))
  • DDL語句 建表/約束、存儲過程或函數
  • 數據初始化 一定數量的
  • 測試存儲過程/函數 截圖記錄
  • 實驗體會

正文

根據項目需求簡述,我們可以得出以下幾條基本的結論:

  • 職工與工程之間的關係: 多對多

  • 職工與職位之間的關係: 多對1

  • 職工與部門之間的關係: 多對1

  • 職位與小時工資率之間的關係: 一對一

  • 工程具有的屬性: 工程號,工程名稱,工程所在地址,起始時間,結束時間

  • 職工具有的屬性:職工號,姓名

  • 部門具有的屬性: 部門編號,部門名稱

因此,我將 職工,工程,部門當做基本的實體,職位與小時工資率相當於職工的一個屬性,工時這個屬性是職工參與工程的過程中的派生屬性

1)需求設計

ER圖

在這裏插入圖片描述

關係模型

1)ER圖轉爲關係表

注:加粗的屬性爲主鍵

工程(工程號,工程名,工程所在地,工程開始時間,工程結束時間)

職工(職工號,職工姓名,職位,小時工資率)

酬金(工程號,職工號,工時)

部門(部門編號,部門名稱)

2)修改表結構

目標:達到3NF範式

顯然 工程表,酬金錶,部門表 滿足 3NF

而職工表中存在 傳遞函數依賴 職工號 -> 職位, 職位 -> 小時工資率 因此我們需要將其拆分達到滿足3NF的要求

所以職工表可以拆成2個表

職工(職工號,職工姓名,職位)

職能 ( 職位,小時工資率)

3)最終關係表

注(加粗代表主鍵,下劃線代表外鍵)

工程表(工程號,工程名,工程所在地,工程開始時間,工程結束時間)

職工表(職工號,職工姓名,職位, 部門編號

職能表 ( 職位,小時工資率)

酬金錶(工程號職工號,工時)

部門表(部門編號,部門名稱)

2)數據插入

建表插入數據的代碼見附件中的sql文件

已插入的數據如下

mysql> select * from department;
+-----+--------+
| dno | dname  |
+-----+--------+
| CW  | 財務部 |
| RS  | 人事部 |
| SC  | 市場部 |
| YF  | 研發部 |
+-----+--------+
4 rows in set (0.00 sec)

mysql> select * from employee;
+------+-------+--------+-----+
| eno  | ename | epost  | dno |
+------+-------+--------+-----+
| CW01 | 方平  | 會計   | CW  |
| RS01 | 張峯  | 主任   | RS  |
| SC01 | 楚陽  | 業務員 | SC  |
| SC02 | 寧缺  | 服務員 | SC  |
| YF01 | 君陌  | 技術員 | YF  |
+------+-------+--------+-----+
5 rows in set (0.00 sec)

mysql> select * from job;
+--------+----------+
| epost  | hourrate |
+--------+----------+
| 業務員 | 250      |
| 主任   | 500      |
| 會計   | 200      |
| 技術員 | 300      |
| 服務員 | 80       |
+--------+----------+
5 rows in set (0.00 sec)

mysql> select * from project;
+-----+----------+-------+------------+------------+
| pno | pname    | paddr | pstart     | pfinal     |
+-----+----------+-------+------------+------------+
| 001 | house    | 寧波  | 2020-04-11 | 2020-08-11 |
| 002 | hospital | 杭州  | 2020-03-30 | 2021-04-03 |
| 003 | store    | 溫州  | 2020-01-24 | 2020-06-28 |
| 004 | park     | 上海  | 2020-01-01 | 2020-11-24 |
| 005 | bigdata  | 東北  | 2020-03-15 | 2020-12-31 |
+-----+----------+-------+------------+------------+
5 rows in set (0.00 sec)

mysql> select * from reward;
+-----+------+----------+
| pno | eno  | worktime |
+-----+------+----------+
| 001 | CW01 | 5        |
| 001 | SC02 | 8        |
| 002 | SC01 | 6        |
| 002 | YF01 | 7        |
| 003 | RS01 | 4        |
| 003 | YF01 | 6        |
| 004 | CW01 | 6        |
| 004 | RS01 | 8        |
| 004 | SC01 | 3        |
| 005 | CW01 | 7        |
| 005 | SC02 | 4        |
| 005 | YF01 | 3        |
+-----+------+----------+
12 rows in set (0.00 sec)

函數function1

1.設計一個存儲過程(函數),以工程編號作爲輸入參數,實現計算某工程所支付的工人酬金。沒有該工程返回-1

代碼
def func1(pno):
    try:
        conn = mysql.connector.connect(**config)
        print('connect successful!')
        print('=='*50)
        # 使用cursor()方法獲取操作遊標 
        cursor = conn.cursor()
        # 記錄開始時間
        start=time.time()
        # 執行SQL語句 
        cursor.execute(f"SELECT employee.ename ename,hourrate,worktime FROM job,employee,reward where reward.pno='{pno}'and reward.eno=employee.eno and employee.epost=job.epost;")
        # 獲取所有記錄列表
        results = cursor.fetchall()
        results=np.array(results)
        if len(results) == 0:
            print('工程號不存在')
        else:
            s = 0
            for li in results:
                name = li[0]
                money = int(li[1])*int(li[2])
                s += money
                print(f'應該支付{name}的薪金是:{money}元')
            print(f'編號爲{pno}的項目共支付工人薪金:{s}元')
    except:
        print("Error: unable to fecth data")
    finally:
        try:
            # 關閉數據庫連接
            print('=='*50)
            print('try to close connect...')
            conn.close()
            print('connect closed!')
            # 打印程序運行時間
            print(f'Run time: {time.time()-start:.6f}s')
        except:
            pass
測試結果在這裏插入圖片描述

函數function2

2.實現員工變更部門的存儲過程,成功返回 1,否則返回0;變更過程計入檔案;職工號/變更類型/原先部分(新增null)/新的部門(離開null)/日期/經手人

這裏的檔案我們選擇新建一個change表

change (職工號,變更類型,原先部分(新增null),新的部門(離開null),日期,經手人)

這道題有2個要求,一個是對職工表的修改,一個是記錄過程進入檔案

代碼
def func2(eno,change_reason,new_dno,who):
    try:
        conn = mysql.connector.connect(**config)
        print('connect successful!')
        print('=='*50)
        # 使用cursor()方法獲取操作遊標 
        cursor = conn.cursor()
        # 記錄開始時間
        start=time.time()
        # 執行SQL語句 
        cursor.execute(f"SELECT dno FROM employee as e where eno = '{eno}';")
        # 獲取所有記錄列表
        results = cursor.fetchall()
        if len(results) == 0:
            results = 'null' # 新人加入,插入emp表
            sql = f"INSERT INTO `salary`.`employee` (`eno`, `dno`) VALUES ('{eno}', '{new_dno}');"
            cursor.execute(sql)
            conn.commit()
            print('新人加入成功')
        else:
            results = results[0][0] # 獲取舊的 dno
            print(results)
            sql = f"UPDATE `salary`.`employee` SET `dno` = '{new_dno}' WHERE (`eno` = '{eno}');"
            cursor.execute(sql)
            conn.commit()
            print('修改部門成功')
        date = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
        sql = f"INSERT INTO `salary`.`message` (`eno`, `reason`, `olddno`, `newdno`, `date`, `who`) VALUES ('{eno}', '{change_reason}', '{results}', '{new_dno}', '{date}', '{who}');"
        cursor.execute(sql)
        conn.commit()
        print('登記完成')
    except:
        print("Error: unable to fecth data")
    finally:
        try:
            # 關閉數據庫連接
            print('=='*50)
            print('try to close connect...')
            conn.close()
            print('connect closed!')
            # 打印程序運行時間
            print(f'Run time: {time.time()-start:.6f}s')
        except:
            pass
測試結果

這是現在的employee表,而message仍是個空表,我們看看接下來他發生的變化

eno ename epost dno
CW01 方平 會計 CW
RS01 張峯 主任 RS
SC01 楚陽 業務員 SC
SC02 寧缺 服務員 SC
YF01 君陌 技術員 YF

在這裏插入圖片描述
上圖可以看到我們將新人加入了部門,這裏因爲不知道新人的名字和職位,如果按之前的插入會出現問題,所以在這一步的時候我修改了表的結構,讓ename和epost可以爲空值

在這裏插入圖片描述

我們可以看出,舊員工更換部門的操作也是成功的

函數function3

3.員工參加工程的上班和下班 存儲過程/函數(注意時間點 早上6:之前和晚上12點後 不允許操作,當天沒有上班的不允許下班的操作…)

這裏新建一個表 來記錄員工每天的簽到情況

status (id(自增長),員工號,日期 , 是否簽到,是否簽退)

Y表示已簽到/簽退

N表示未簽到/簽退

這裏我認爲題目沒有說清楚具體的簽到時間和簽退時間區間,僅僅說了24.00-6.00不允許操作,所以我加上了flag參數來表示員工的舉動,flag = 0代表簽到,flag= 1代表簽退,默認的值爲0

代碼
def func3(eno,flag=0):
    try:
        conn = mysql.connector.connect(**config)
        print('connect successful!')
        print('=='*50)
        # 使用cursor()方法獲取操作遊標 
        cursor = conn.cursor()
        # 記錄開始時間
        start=time.time()
        day = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))[:10]# 獲取年月日
        hour = datetime.datetime.now().hour # 獲取小時
        minute = datetime.datetime.now().minute # 分
        second = datetime.datetime.now().second # 秒
        print(day,hour,minute,second)
        if 6 <= hour <= 24: # 早上6點到晚上24.00之間
            if (minute > 0 or second > 0 ) and hour == 24:  #超過24.00
                print('您已經超時,不允許操作')
            else:
                if flag == 0: # 簽到,插入數據
                    sql = f"INSERT INTO `salary`.`status` (`eno`, `date`, `ifup`) VALUES ('{eno}', '{day}', 'Y');"
                    cursor.execute(sql)
                    conn.commit()
                    print(f'{eno}已經成功簽到!')
                else: # 簽退
                    sql = f"SELECT ifup FROM salary.status where eno ='{eno}';"
                    cursor.execute(sql)
                    results = cursor.fetchall()
                    if len(results) == 0:
                        print('抱歉,您尚未簽到')
                    else:
                        sql = f"UPDATE `salary`.`status` SET `ifdown` = 'Y' WHERE (`eno` = '{eno}');"
                        cursor.execute(sql)
                        conn.commit()
                        print(f'{eno}已經簽退成功!')
    except:
        print("Error: unable to fecth data")
    finally:
        try:
            # 關閉數據庫連接
            print('=='*50)
            print('try to close connect...')
            conn.close()
            print('connect closed!')
            # 打印程序運行時間
            print(f'Run time: {time.time()-start:.6f}s')
        except:
            pass
測試結果

在這裏插入圖片描述
可以看出現在 ifdown字段是空值,下面進行簽退操作
在這裏插入圖片描述
上圖可以看到 ifdown字段加上了Y
在這裏插入圖片描述

上圖看出,如果沒有簽到的用戶去簽退,將會給出提示

3)最終結果 綜合

def main():
    while True:
        a = input('請輸入序號進行操作:\n1.查看某工程支付的工人佣金\n2.員工變更部門\n3.員工簽到/退\n4.查看更多信息\n5.退出操作\n')  
        if a == '1':
            pno = input('請輸入想要查詢的工程號:')
            func1(pno)
        elif a == '2':
            eno,change_reason,new_dno,who=input('請按順序輸入以下信息(以逗號間隔)\n職工號,變更類型,新的部門,經手人:').split(',')
            func2(eno,change_reason,new_dno,who)
        elif a == '3':
            eno = input('請輸入你的職工號:')
            flag = int(input('如想簽到請輸0,簽退請輸1:'))
            func3(eno,flag=flag)
        elif a == '4':
            print('請輸入sql語句來進行你想查看的操作:')
            sql = input()
            executing(sql)
        else:
            print('感謝使用')
            break

請輸入序號進行操作:
1.查看某工程支付的工人佣金
2.員工變更部門
3.員工簽到/退
4.查看更多信息
5.退出操作
1
請輸入想要查詢的工程號:004
connect successful!
====================================================================================================
應該支付方平的薪金是:1200元
應該支付張峯的薪金是:4000元
應該支付楚陽的薪金是:750元
編號爲004的項目共支付工人薪金:5950元
====================================================================================================
try to close connect...
connect closed!
Run time: 0.000995s
請輸入序號進行操作:
1.查看某工程支付的工人佣金
2.員工變更部門
3.員工簽到/退
4.查看更多信息
5.退出操作
2
請按順序輸入以下信息(以逗號間隔)
職工號,變更類型,新的部門,經手人:YF01,更換部門,RS,董事長
connect successful!
====================================================================================================
修改部門成功,YF01員工已經從YF部門加入RS部門!
登記完成
====================================================================================================
try to close connect...
connect closed!
Run time: 0.008980s
請輸入序號進行操作:
1.查看某工程支付的工人佣金
2.員工變更部門
3.員工簽到/退
4.查看更多信息
5.退出操作
3
請輸入你的職工號:SC01
如想簽到請輸0,簽退請輸1:0
connect successful!
====================================================================================================
2020-04-11 18 59 14
SC01已經成功簽到!
====================================================================================================
try to close connect...
connect closed!
Run time: 0.002995s
請輸入序號進行操作:
1.查看某工程支付的工人佣金
2.員工變更部門
3.員工簽到/退
4.查看更多信息
5.退出操作
3
請輸入你的職工號:SC01
如想簽到請輸0,簽退請輸1:1
connect successful!
====================================================================================================
2020-04-11 18 59 21
SC01已經簽退成功!
====================================================================================================
try to close connect...
connect closed!
Run time: 0.022945s
請輸入序號進行操作:
1.查看某工程支付的工人佣金
2.員工變更部門
3.員工簽到/退
4.查看更多信息
5.退出操作
4
請輸入sql語句來進行你想查看的操作:
SELECT * FROM salary.employee;
connect successful!
begin to execute
[['CW01' '方平' '會計' 'CW']
 ['RS01' '張峯' '主任' 'YF']
 ['RS02' None None 'CW']
 ['RS03' None None 'CW']
 ['SC01' '楚陽' '業務員' 'SC']
 ['SC02' '寧缺' '服務員' 'SC']
 ['YF01' '君陌' '技術員' 'RS']]
try to close connect...
connect closed!
Run time: 0.000997s
請輸入序號進行操作:
1.查看某工程支付的工人佣金
2.員工變更部門
3.員工簽到/退
4.查看更多信息
5.退出操作
5
感謝使用

4)實驗體會

本次實驗讓我鞏固了mysql的操作,在上學期的學習中,我已經熟練的掌握了命令行對mysql的各種操作,這次實驗是可以說是一次很好的複習,從需求分析開始到建表,再到最後的編寫函數,花費了我好幾個小時的時間,但是成功的結果讓我收穫滿滿

除去上學期所學的命令行的一些操作,在這次實驗中,我結合了python操縱mysql,並且學習了mysql圖形界面工具workbench的使用,它們在一定程度上使得我對mysql的操作更加方便

附件1:salay.sql (裏面包括了建表和插入數據的操作) 下載入口點此進入

附件2:工程薪資基本項目管理.ipynb(裏面包括了函數實現的所有代碼)下載入口點此進入

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