數據庫課程設計(python操控)
------必做內容(工程薪資基本項目管理):
前言(課設要求)
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
(裏面包括了函數實現的所有代碼)下載入口點此進入