板凳-------Mysql cookbook學習 (十二--------3_2)

3.3鏈接表 結構 P79頁

用一個類圖來表示EmployeeNode類的結構,展示其屬性和關系:
plaintext
+-----------------------------------------+
|             EmployeeNode                |
+-----------------------------------------+
| - emp_no: int                           |
| - birth_date: date                      |
| - first_name: str                       |
| - last_name: str                        |
| - gender: str                           |
| - hire_date: date                       |
| - departments: list                     |
| - manager_of: list                      |
| - salaries: list                        |
| - titles: list                          |
+-----------------------------------------+
| + __init__(emp_no, birth_date, ...)     |
| + __repr__(): str                       |
+-----------------------------------------+|              |             |v              v             v
+----------------+----------------+----------------+
|  departments   |   manager_of   |   salaries     |
|  (部門關系)    |  (管理關系)    |  (薪資歷史)    |
+----------------+----------------+----------------+|v
+----------------+
|    titles      |
|  (職位歷史)    |
+----------------+這個圖表展示了:
EmployeeNode類的核心屬性:
基本信息:員工編號 (emp_no)、出生日期 (birth_date)、姓名 (first_name/last_name)、性別 (gender)、入職日期 (hire_date)
關系屬性:部門列表 (departments)、管理部門列表 (manager_of)、薪資歷史 (salaries)、職位歷史 (titles)
類的方法:
構造方法__init__用于初始化對象
__repr__方法用于返回對象的字符串表示
關系說明:
departments:存儲員工所屬的部門及任職時間信息
manager_of:存儲員工管理的部門及管理時間信息
salaries:存儲員工的薪資歷史記錄
titles:存儲員工的職位變遷歷史
這些屬性共同構成了一個員工的完整檔案,包括基本信息和各種職業相關的關系信息。
程序類關系總覽圖
plaintext
┌───────────────────┐       ┌───────────────────┐       ┌───────────────────┐
│   EmployeeNode    │       │   DepartmentNode  │       │    SalaryNode     │
├───────────────────┤       ├───────────────────┤       ├───────────────────┤
│ - emp_no          │       │ - dept_no         │       │ - emp_no          │
│ - birth_date      │       │ - dept_name       │       │ - salary          │
│ - first_name      │       │ - employees       │?──────┤ - from_date       │
│ - last_name       │       │ - managers        │       │ - to_date         │
│ - gender          │       └───────────────────┘       └───────────────────┘
│ - hire_date       │                ▲                        ▲
│ - departments     │?───────────────┘                        │
│ - manager_of      │                                         │
│ - salaries        │?────────────────────────────────────────┘
│ - titles          │?────────────────────────────────────────┐
└───────────────────┘                                         ││
┌───────────────────┐       ┌───────────────────┐             │
│    TitleNode      │       │   EmployeeGraph   │             │
├───────────────────┤       ├───────────────────┤             │
│ - emp_no          │       │ - connection      │             │
│ - title           │       │ - employees       │?────────────┘
│ - from_date       │       │ - departments     │
│ - to_date         │       │ - employees_by_name│
└───────────────────┘       └───────────────────┘▲                         ▲│                         │└─────────────────────────┘(被管理/被構建)圖表說明
1. 核心節點類(數據實體)
EmployeeNode(員工節點)
存儲員工基本信息(編號、姓名、出生日期等)。
通過列表屬性關聯其他實體:
departments:關聯所屬的DepartmentNode及任職時間。
manager_of:關聯管理的DepartmentNode及管理時間。
salaries:關聯對應的SalaryNode(薪資歷史)。
titles:關聯對應的TitleNode(職位歷史)。
DepartmentNode(部門節點)
存儲部門基本信息(編號、名稱)。
通過列表屬性關聯員工:
employees:關聯屬于該部門的EmployeeNode及任職時間。
managers:關聯管理該部門的EmployeeNode及管理時間。
SalaryNode(薪資節點)
存儲單條薪資記錄(金額、生效 / 截止日期),通過emp_no關聯EmployeeNode。
TitleNode(職位節點)
存儲單條職位記錄(職位名稱、生效 / 截止日期),通過emp_no關聯EmployeeNode。
2. 管理類(核心邏輯)
EmployeeGraph(員工關系圖)
負責數據庫連接、數據加載和關系構建。
存儲所有節點的集合:
employees:以emp_no為鍵的EmployeeNode字典。
departments:以dept_no為鍵的DepartmentNode字典。
employees_by_name:以姓名為鍵的EmployeeNode字典(方便按姓名查詢)。
核心方法:通過數據庫查詢,將分散的節點數據關聯起來(如員工 - 部門、員工 - 薪資等關系)。
3. 關系總結
一對一關聯:SalaryNode和TitleNode通過emp_no綁定到特定EmployeeNode。
一對多關聯:
一個DepartmentNode對應多個EmployeeNode(員工)和多個EmployeeNode(經理)。
一個EmployeeNode對應多個DepartmentNode(多部門任職)、多個SalaryNode(薪資變動)、多個TitleNode(職位變動)。
管理關系:EmployeeGraph是整個程序的 “引擎”,負責初始化所有節點并建立它們之間的關聯。
通過這個圖表,可以直觀理解程序的設計思路:用面向對象的方式將數據庫中的表結構映射為節點類,再通過EmployeeGraph類構建節點間的關聯,最終形成一個可查詢的員工關系網絡。
這段代碼實現了一個員工信息管理系統,通過 MySQL 數據庫構建了一個員工關系圖,能夠加載和展示員工、部門、薪資和職位等信息及其關系。下面我來逐句講解:
python
運行
import mysql.connector
from mysql.connector import Error
from datetime import date
導入所需的庫:mysql.connector用于連接 MySQL 數據庫,Error用于捕獲數據庫錯誤,date用于處理日期數據
python
運行
# 首先定義所有節點類
class EmployeeNode:def __init__(self, emp_no, birth_date, first_name, last_name, gender, hire_date):self.emp_no = emp_noself.birth_date = birth_dateself.first_name = first_nameself.last_name = last_nameself.gender = genderself.hire_date = hire_dateself.departments = []  # 員工所屬的部門列表self.manager_of = []   # 員工管理的部門列表self.salaries = []     # 員工的薪資歷史self.titles = []       # 員工的職位歷史
定義EmployeeNode類,用于表示員工節點
__init__方法初始化員工的基本信息
同時初始化了幾個列表屬性,用于存儲與該員工相關的部門、管理關系、薪資和職位信息
python
運行def __repr__(self):return f"<Employee {self.emp_no}: {self.first_name} {self.last_name}>"
定義__repr__方法,用于返回員工對象的字符串表示,方便調試和打印
python
運行
class DepartmentNode:def __init__(self, dept_no, dept_name):self.dept_no = dept_noself.dept_name = dept_nameself.employees = []  # 部門中的員工列表self.managers = []   # 部門的經理列表
定義DepartmentNode類,用于表示部門節點
__init__方法初始化部門的基本信息
初始化了兩個列表屬性,用于存儲部門中的員工和經理信息
python
運行def __repr__(self):return f"<Department {self.dept_no}: {self.dept_name}>"
定義__repr__方法,用于返回部門對象的字符串表示
python
運行
class SalaryNode:def __init__(self, emp_no, salary, from_date, to_date):self.emp_no = emp_noself.salary = salaryself.from_date = from_dateself.to_date = to_date
定義SalaryNode類,用于表示薪資節點
__init__方法初始化薪資信息,包括員工編號、薪資數額、生效日期和截止日期
python
運行def __repr__(self):return f"<Salary {self.salary} from {self.from_date} to {self.to_date}>"
定義__repr__方法,用于返回薪資對象的字符串表示
python
運行
class TitleNode:def __init__(self, emp_no, title, from_date, to_date):self.emp_no = emp_noself.title = titleself.from_date = from_dateself.to_date = to_date
定義TitleNode類,用于表示職位節點
__init__方法初始化職位信息,包括員工編號、職位名稱、生效日期和截止日期
python
運行def __repr__(self):return f"<Title {self.title} from {self.from_date} to {self.to_date}>"
定義__repr__方法,用于返回職位對象的字符串表示
python
運行
# 然后定義EmployeeGraph類
class EmployeeGraph:def __init__(self, host, database, user, password):try:self.connection = mysql.connector.connect(host=host,database=database,user=user,password=password)self.employees = {}  # 存儲員工對象,鍵為員工編號self.departments = {}  # 存儲部門對象,鍵為部門編號self.employees_by_name = {}  # 存儲員工對象,鍵為員工姓名(小寫)except Error as e:print(f"Error connecting to MySQL: {e}")
定義EmployeeGraph類,用于構建和管理員工關系圖
__init__方法接收數據庫連接參數,嘗試連接 MySQL 數據庫
初始化了三個字典屬性,用于存儲員工、部門對象,以及按姓名索引的員工對象
使用try-except捕獲數據庫連接錯誤
python
運行def load_employees(self):query = "SELECT * FROM employees"cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = EmployeeNode(emp_no=row['emp_no'],birth_date=row['birth_date'],first_name=row['first_name'],last_name=row['last_name'],gender=row['gender'],hire_date=row['hire_date'])self.employees[row['emp_no']] = empname_key = f"{row['first_name']} {row['last_name']}".lower()self.employees_by_name[name_key] = empcursor.close()
定義load_employees方法,用于從數據庫加載員工信息
執行 SQL 查詢獲取所有員工記錄
為每條記錄創建EmployeeNode對象,并存儲到employees和employees_by_name字典中
最后關閉游標
python
運行def load_departments(self):query = "SELECT * FROM departments"cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:dept = DepartmentNode(dept_no=row['dept_no'],dept_name=row['dept_name'])self.departments[row['dept_no']] = deptcursor.close()
定義load_departments方法,用于從數據庫加載部門信息
執行 SQL 查詢獲取所有部門記錄
為每條記錄創建DepartmentNode對象,并存儲到departments字典中
最后關閉游標
python
運行def build_dept_emp_relationships(self):query = """SELECT de.emp_no, de.dept_no, de.from_date, de.to_date, d.dept_name FROM dept_emp deJOIN departments d ON de.dept_no = d.dept_no"""cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = self.employees.get(row['emp_no'])dept = self.departments.get(row['dept_no'])if emp and dept:dept.employees.append({'employee': emp,'from_date': row['from_date'],'to_date': row['to_date']})emp.departments.append({'department': dept,'from_date': row['from_date'],'to_date': row['to_date']})cursor.close()
定義build_dept_emp_relationships方法,用于構建部門和員工之間的關系
執行 SQL 查詢獲取員工與部門的關聯信息
對每條記錄,獲取對應的員工和部門對象
如果兩者都存在,則在部門對象的employees列表和員工對象的departments列表中添加關聯信息
最后關閉游標
python
運行def build_dept_manager_relationships(self):query = """SELECT dm.emp_no, dm.dept_no, dm.from_date, dm.to_date, d.dept_name FROM dept_manager dmJOIN departments d ON dm.dept_no = d.dept_no"""cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = self.employees.get(row['emp_no'])dept = self.departments.get(row['dept_no'])if emp and dept:dept.managers.append({'manager': emp,'from_date': row['from_date'],'to_date': row['to_date']})emp.manager_of.append({'department': dept,'from_date': row['from_date'],'to_date': row['to_date']})cursor.close()
定義build_dept_manager_relationships方法,用于構建部門和經理之間的關系
執行 SQL 查詢獲取經理與部門的關聯信息
對每條記錄,獲取對應的員工 (經理) 和部門對象
如果兩者都存在,則在部門對象的managers列表和員工對象的manager_of列表中添加關聯信息
最后關閉游標
python
運行def load_salaries(self):query = "SELECT * FROM salaries"cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = self.employees.get(row['emp_no'])if emp:salary = SalaryNode(emp_no=row['emp_no'],salary=row['salary'],from_date=row['from_date'],to_date=row['to_date'])emp.salaries.append(salary)cursor.close()
定義load_salaries方法,用于加載員工的薪資信息
執行 SQL 查詢獲取所有薪資記錄
對每條記錄,獲取對應的員工對象
如果員工存在,則創建SalaryNode對象,并添加到員工的salaries列表中
最后關閉游標
python
運行def load_titles(self):query = "SELECT * FROM titles"cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = self.employees.get(row['emp_no'])if emp:title = TitleNode(emp_no=row['emp_no'],title=row['title'],from_date=row['from_date'],to_date=row['to_date'])emp.titles.append(title)cursor.close()
定義load_titles方法,用于加載員工的職位信息
執行 SQL 查詢獲取所有職位記錄
對每條記錄,獲取對應的員工對象
如果員工存在,則創建TitleNode對象,并添加到員工的titles列表中
最后關閉游標
python
運行def build_graph(self):self.load_employees()self.load_departments()self.build_dept_emp_relationships()self.build_dept_manager_relationships()self.load_salaries()self.load_titles()
定義build_graph方法,用于構建完整的員工關系圖
依次調用前面定義的各個方法,加載和關聯所有數據
python
運行def close(self):if hasattr(self, 'connection') and self.connection.is_connected():self.connection.close()
定義close方法,用于關閉數據庫連接
檢查連接是否存在且處于連接狀態,如果是則關閉連接
python
運行
# 使用示例
if __name__ == "__main__":# 初始化并構建圖graph = EmployeeGraph(host="localhost",database="employees",user="root",password="root")graph.build_graph()
當腳本作為主程序運行時的代碼
創建EmployeeGraph對象,傳入數據庫連接參數
調用build_graph方法構建員工關系圖
python
運行# 示例查詢if 10001 in graph.employees:emp = graph.employees[10001]print(emp)print("所屬部門:", emp.departments)print("管理的部門:", emp.manager_of)print("薪資歷史:", emp.salaries)print("職位歷史:", emp.titles)
示例查詢代碼,檢查員工編號為 10001 的員工是否存在
如果存在,則打印該員工的基本信息、所屬部門、管理的部門、薪資歷史和職位歷史
python
運行# 分析職業發展print(f"\n職業發展分析 - {emp.first_name} {emp.last_name}")print(f"入職時間: {emp.hire_date}")print(f"當前職位: {emp.titles[-1].title if emp.titles else '無記錄'}")print(f"當前部門: {emp.departments[-1]['department'].dept_name if emp.departments else '無記錄'}")if emp.salaries:growth = (emp.salaries[-1].salary / emp.salaries[0].salary) - 1print(f"薪資增長: {emp.salaries[0].salary}{emp.salaries[-1].salary} (增長{growth:.1%})")
對員工進行職業發展分析
打印入職時間、當前職位 (假設最后一個職位是當前職位)、當前部門 (假設最后一個部門是當前部門)
計算并打印薪資增長情況
python
運行# 關閉連接graph.close()最后調用close方法關閉數據庫連接
這個程序通過面向對象的方式構建了一個員工關系圖,將數據庫中的員工、部門、薪資和職位信息及其關系映射為內存中的對象模型,方便進行各種查詢和分析操作。
import mysql.connector
from mysql.connector import Error
from datetime import date
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd# 首先定義所有節點類
class EmployeeNode:def __init__(self, emp_no, birth_date, first_name, last_name, gender, hire_date):self.emp_no = emp_noself.birth_date = birth_dateself.first_name = first_nameself.last_name = last_nameself.gender = genderself.hire_date = hire_dateself.departments = []self.manager_of = []self.salaries = []self.titles = []def __repr__(self):return f"<Employee {self.emp_no}: {self.first_name} {self.last_name}>"class DepartmentNode:def __init__(self, dept_no, dept_name):self.dept_no = dept_noself.dept_name = dept_nameself.employees = []self.managers = []def __repr__(self):return f"<Department {self.dept_no}: {self.dept_name}>"class SalaryNode:def __init__(self, emp_no, salary, from_date, to_date):self.emp_no = emp_noself.salary = salaryself.from_date = from_dateself.to_date = to_datedef __repr__(self):return f"<Salary {self.salary} from {self.from_date} to {self.to_date}>"class TitleNode:def __init__(self, emp_no, title, from_date, to_date):self.emp_no = emp_noself.title = titleself.from_date = from_dateself.to_date = to_datedef __repr__(self):return f"<Title {self.title} from {self.from_date} to {self.to_date}>"# 然后定義EmployeeGraph類
class EmployeeGraph:def __init__(self, host, database, user, password):try:self.connection = mysql.connector.connect(host=host,database=database,user=user,password=password)self.employees = {}self.departments = {}self.employees_by_name = {}except Error as e:print(f"Error connecting to MySQL: {e}")def load_employees(self):query = "SELECT * FROM employees"cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = EmployeeNode(emp_no=row['emp_no'],birth_date=row['birth_date'],first_name=row['first_name'],last_name=row['last_name'],gender=row['gender'],hire_date=row['hire_date'])self.employees[row['emp_no']] = empname_key = f"{row['first_name']} {row['last_name']}".lower()self.employees_by_name[name_key] = empcursor.close()def load_departments(self):query = "SELECT * FROM departments"cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:dept = DepartmentNode(dept_no=row['dept_no'],dept_name=row['dept_name'])self.departments[row['dept_no']] = deptcursor.close()def build_dept_emp_relationships(self):query = """SELECT de.emp_no, de.dept_no, de.from_date, de.to_date, d.dept_name FROM dept_emp deJOIN departments d ON de.dept_no = d.dept_no"""cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = self.employees.get(row['emp_no'])dept = self.departments.get(row['dept_no'])if emp and dept:dept.employees.append({'employee': emp,'from_date': row['from_date'],'to_date': row['to_date']})emp.departments.append({'department': dept,'from_date': row['from_date'],'to_date': row['to_date']})cursor.close()def build_dept_manager_relationships(self):query = """SELECT dm.emp_no, dm.dept_no, dm.from_date, dm.to_date, d.dept_name FROM dept_manager dmJOIN departments d ON dm.dept_no = d.dept_no"""cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = self.employees.get(row['emp_no'])dept = self.departments.get(row['dept_no'])if emp and dept:dept.managers.append({'manager': emp,'from_date': row['from_date'],'to_date': row['to_date']})emp.manager_of.append({'department': dept,'from_date': row['from_date'],'to_date': row['to_date']})cursor.close()def load_salaries(self):query = "SELECT * FROM salaries"cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = self.employees.get(row['emp_no'])if emp:salary = SalaryNode(emp_no=row['emp_no'],salary=row['salary'],from_date=row['from_date'],to_date=row['to_date'])emp.salaries.append(salary)cursor.close()def load_titles(self):query = "SELECT * FROM titles"cursor = self.connection.cursor(dictionary=True)cursor.execute(query)for row in cursor:emp = self.employees.get(row['emp_no'])if emp:title = TitleNode(emp_no=row['emp_no'],title=row['title'],from_date=row['from_date'],to_date=row['to_date'])emp.titles.append(title)cursor.close()def build_graph(self):self.load_employees()self.load_departments()self.build_dept_emp_relationships()self.build_dept_manager_relationships()self.load_salaries()self.load_titles()def close(self):if hasattr(self, 'connection') and self.connection.is_connected():self.connection.close()# 使用示例
if __name__ == "__main__":# 初始化并構建圖graph = EmployeeGraph(host="localhost",database="employees",user="root",password="root")graph.build_graph()# 示例查詢if 10001 in graph.employees:emp = graph.employees[10001]print(emp)print("所屬部門:", emp.departments)print("管理的部門:", emp.manager_of)print("薪資歷史:", emp.salaries)print("職位歷史:", emp.titles)# 分析職業發展print(f"\n職業發展分析 - {emp.first_name} {emp.last_name}")print(f"入職時間: {emp.hire_date}")print(f"當前職位: {emp.titles[-1].title if emp.titles else '無記錄'}")print(f"當前部門: {emp.departments[-1]['department'].dept_name if emp.departments else '無記錄'}")if emp.salaries:growth = (emp.salaries[-1].salary / emp.salaries[0].salary) - 1print(f"薪資增長: {emp.salaries[0].salary}{emp.salaries[-1].salary} (增長{growth:.1%})")# 準備薪資數據
salaries = emp.salaries
salary_data = [(s.from_date.year, s.salary) for s in salaries]
df_salary = pd.DataFrame(salary_data, columns=['Year', 'Salary'])# 創建圖表
plt.figure(figsize=(12, 6))
sns.lineplot(data=df_salary, x='Year', y='Salary', marker='o')# 添加標注
for i, row in df_salary.iterrows():plt.text(row['Year'], row['Salary'], f"{row['Salary']:,}", ha='center', va='bottom')plt.title(f"{emp.first_name} {emp.last_name} 薪資增長趨勢 (1986-2002)")
plt.xlabel("年份")
plt.ylabel("薪資 ($)")
plt.grid(True)
plt.tight_layout()
plt.show()# 關閉連接graph.close()
===============================================
<Employee 10001: Georgi Facello>
所屬部門: [{'department': <Department d005: Development>, 'from_date': datetime.date(1986, 6, 26), 'to_date': datetime.date(9999, 1, 1)}]
管理的部門: []
薪資歷史: [<Salary 60117 from 1986-06-26 to 1987-06-26>, <Salary 62102 from 1987-06-26 to 1988-06-25>, <Salary 66074 from 1988-06-25 to 1989-06-25>, <Salary 66596 from 1989-06-25 to 1990-06-25>, <Salary 66961 from 1990-06-25 to 1991-06-25>, <Salary 71046 from 1991-06-25 to 1992-06-24>, <Salary 74333 from 1992-06-24 to 1993-06-24>, <Salary 75286 from 1993-06-24 to 1994-06-24>, <Salary 75994 from 1994-06-24 to 1995-06-24>, <Salary 76884 from 1995-06-24 to 1996-06-23>, <Salary 80013 from 1996-06-23 to 1997-06-23>, <Salary 81025 from 1997-06-23 to 1998-06-23>, <Salary 81097 from 1998-06-23 to 1999-06-23>, <Salary 84917 from 1999-06-23 to 2000-06-22>, <Salary 85112 from 2000-06-22 to 2001-06-22>, <Salary 85097 from 2001-06-22 to 2002-06-22>, <Salary 88958 from 2002-06-22 to 9999-01-01>]
職位歷史: [<Title Senior Engineer from 1986-06-26 to 9999-01-01>]職業發展分析 - Georgi Facello
入職時間: 1986-06-26
當前職位: Senior Engineer
當前部門: Development
薪資增長: 6011788958 (增長48.0%)================================================
這個輸出結果展示了員工Georgi Facello(員工號10001)的完整職業發展數據,分析如下:
職業發展概況
1.	基本信息:
o	姓名:Georgi Facello
o	入職時間:1986626日
o	當前狀態:仍在職(9999-01-01是數據庫表示當前的標準方式)
2.	部門信息:
o	所屬部門:Development (d005)
o	從1986626日至今一直在同一部門
o	沒有擔任過管理職務(管理的部門為空列表)
3.	職位發展:
o	職位:Senior Engineer
o	從入職至今一直保持同一職位
o	沒有職位變更記錄
4.	薪資變化:
o	起薪:60,117 (1986)
o	當前薪資:88,958 (2002年調整后)
o	總增長幅度:48.0%
o	共經歷17次薪資調整
o	平均每年增長約3.0%(按16年計算)
詳細薪資調整分析
text
復制
下載
1986-1987: 60,11762,102 (+3.3%)
1987-1988: 62,10266,074 (+6.4%)
1988-1989: 66,07466,596 (+0.8%)
1989-1990: 66,59666,961 (+0.5%)
1990-1991: 66,96171,046 (+6.1%)
1991-1992: 71,04674,333 (+4.6%)
1992-1993: 74,33375,286 (+1.3%)
1993-1994: 75,28675,994 (+0.9%)
1994-1995: 75,99476,884 (+1.2%)
1995-1996: 76,88480,013 (+4.1%)
1996-1997: 80,01381,025 (+1.3%)
1997-1998: 81,02581,097 (+0.1%)
1998-1999: 81,09784,917 (+4.7%)
1999-2000: 84,91785,112 (+0.2%)
2000-2001: 85,11285,097 (-0.02%)
2001-2002: 85,09788,958 (+4.5%)
職業發展特點
1.	穩定性強:
o	36+任職同一部門
o	長期保持Senior Engineer職位
2.	薪資增長模式:
o	早期增長較快(前5年增長約18.5%)
o	中期增長平穩(1991-2002年平均約3.5%)
o	2000-2001年出現唯一一次微小降薪(可能是數據錯誤或特殊調整)
3.	職業發展建議:
o	可考慮橫向發展(跨部門項目)
o	如尋求晉升,可能需要拓展管理技能
o	當前薪資增長率已趨于穩定,可能需要新的職業突破點
Python的matplotlib和seaborn庫來創建專業圖表。
1. 薪資增長趨勢圖(折線圖)
python
復制
下載
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd# 準備薪資數據
salaries = emp.salaries
salary_data = [(s.from_date.year, s.salary) for s in salaries]
df_salary = pd.DataFrame(salary_data, columns=['Year', 'Salary'])# 創建圖表
plt.figure(figsize=(12, 6))
sns.lineplot(data=df_salary, x='Year', y='Salary', marker='o')# 添加標注
for i, row in df_salary.iterrows():plt.text(row['Year'], row['Salary'], f"{row['Salary']:,}", ha='center', va='bottom')plt.title(f"{emp.first_name} {emp.last_name} 薪資增長趨勢 (1986-2002)")
plt.xlabel("年份")
plt.ylabel("薪資 ($)")
plt.grid(True)
plt.tight_layout()
plt.show()

在這里插入圖片描述

  1. 薪資年增長率分析(柱狀圖)
python
復制
下載
# 計算年增長率
df_salary['Growth'] = df_salary['Salary'].pct_change() * 100# 創建圖表
plt.figure(figsize=(12, 6))
bars = plt.bar(df_salary['Year'][1:], df_salary['Growth'][1:], color=['green' if x >0 else 'red' for x in df_salary['Growth'][1:]])# 添加數值標簽
for bar in bars:height = bar.get_height()plt.text(bar.get_x() + bar.get_width()/2., height,f'{height:.1f}%',ha='center', va='bottom')plt.title("年度薪資增長率 (%)")
plt.xlabel("年份")
plt.ylabel("增長率 (%)")
plt.axhline(0, color='black', linewidth=0.5)
plt.grid(axis='y')
plt.show()

在這里插入圖片描述

3. 薪資分布箱線圖(與全公司對比)
python
復制
下載
# 獲取全公司同年入職員工薪資數據(示例)
# 實際應用中需要從數據庫查詢真實數據
company_salaries = {1986: [60117, 65000, 58000, 62000, 59000],2002: [85000, 92000, 88000, 89000, 91000]
}# 創建對比數據
compare_data = {'Year': [1986, 2002, 1986, 2002],'Salary': [emp.salaries[0].salary, emp.salaries[-1].salary, sum(company_salaries[1986])/len(company_salaries[1986]),sum(company_salaries[2002])/len(company_salaries[2002])],'Type': ['Georgi', 'Georgi', '公司平均', '公司平均']
}df_compare = pd.DataFrame(compare_data)# 創建圖表
plt.figure(figsize=(10, 6))
sns.barplot(data=df_compare, x='Year', y='Salary', hue='Type', palette='Set2')plt.title("薪資與公司平均水平對比")
plt.xlabel("年份")
plt.ylabel("薪資 ($)")
plt.legend(title='')
plt.grid(axis='y')
plt.show()
  1. 職業發展路徑圖(甘特圖)
python
復制
下載
from matplotlib.patches import Patch# 準備數據
events = [{"Type": "職位", "Start": emp.titles[0].from_date, "End": emp.titles[0].to_date, "Label": emp.titles[0].title},{"Type": "部門", "Start": emp.departments[0]['from_date'], "End": emp.departments[0]['to_date'], "Label": emp.departments[0]['department'].dept_name}
]# 轉換為DataFrame
df_events = pd.DataFrame(events)# 創建圖表
fig, ax = plt.subplots(figsize=(12, 4))colors = {'職位': 'tab:blue', '部門': 'tab:orange'}
for idx, row in df_events.iterrows():ax.barh(row['Type'], (row['End'] - row['Start']).days/365, left=row['Start'].year + (row['Start'].timetuple().tm_yday-1)/365,color=colors[row['Type']])ax.text((row['Start'].year + row['End'].year)/2, idx, row['Label'], ha='center', va='center', color='white')ax.set_xlim(1985, 2023)
ax.set_title("職業發展時間線")
ax.set_xlabel("年份")
ax.set_yticks(range(len(df_events)))
ax.set_yticklabels(df_events['Type'])
ax.grid(axis='x')# 添加圖例
legend_elements = [Patch(facecolor=colors[k], label=k) for k in colors]
ax.legend(handles=legend_elements, loc='upper right')plt.tight_layout()
plt.show()
  1. 薪資預測(線性回歸)
python
復制
下載
from sklearn.linear_model import LinearRegression
import numpy as np# 準備數據
X = np.array(df_salary['Year']).reshape(-1, 1)
y = np.array(df_salary['Salary'])# 訓練模型
model = LinearRegression()
model.fit(X, y)# 預測未來
future_years = np.array([2005, 2010, 2015, 2020]).reshape(-1, 1)
predicted = model.predict(future_years)# 可視化
plt.figure(figsize=(12, 6))
plt.scatter(X, y, color='blue', label='實際薪資')
plt.plot(np.concatenate([X, future_years]), model.predict(np.concatenate([X, future_years]).reshape(-1, 1)),color='red', linestyle='--', label='預測趨勢')plt.title("薪資增長趨勢與預測")
plt.xlabel("年份")
plt.ylabel("薪資 ($)")
plt.legend()
plt.grid(True)# 標注預測值
for year, salary in zip(future_years.flatten(), predicted):plt.text(year, salary, f"{int(salary):,}", ha='center', va='bottom')plt.show()
使用建議
1.	安裝必要庫:
bash
復制
下載
pip install matplotlib seaborn scikit-learn pandas
2.	數據分析擴展:
o	可以添加更多員工數據進行對比分析
o	引入更多機器學習模型(如隨機森林)提高預測準確性
o	添加交互功能(使用Plotly庫)
3.	商業洞察:
o	識別高績效員工成長模式
o	分析薪資增長與職位晉升的關系
o	預測未來人力成本

設計一個員工篩選生成器,可以找出同一年入職的員工。

功能說明
核心功能:get_employees_by_year(): 獲取特定年份入職的所有員工analyze_hire_years(): 統計每年入職人數generate_report(): 生成指定年份區間的入職員工詳細報告visualize_hire_trends(): 可視化每年入職人數趨勢高級功能:支持按年份范圍篩選自動將結果轉換為Pandas DataFrame便于分析提供可視化圖表展示入職趨勢使用場景:python
# 查找所有1995年入職的員工
filter = EmployeeFilter(...)
employees_1995 = filter.get_employees_by_year(1995)# 分析1990-2000年入職情況
report = filter.generate_report(1990, 2000)
print(report.groupby('入職年份')['員工編號'].count())# 找出公司歷史上入職人數最多的年份
stats = filter.analyze_hire_years()
peak_year = max(stats.items(), key=lambda x: x[1])
print(f"入職高峰年: {peak_year[0]}年, {peak_year[1]}人")
import mysql.connector
from mysql.connector import Error
from collections import defaultdict
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import warnings# 1. 解決中文顯示問題(無需外部字體文件)
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 使用系統自帶雅黑字體
plt.rcParams['axes.unicode_minus'] = False  # 解決負號顯示問題# 2. 過濾警告信息
warnings.filterwarnings('ignore', category=UserWarning)class EmployeeFilter:def __init__(self, host, database, user, password, batch_size=50000):"""初始化數據庫連接"""try:self.connection = mysql.connector.connect(host=host,database=database,user=user,password=password)self.employees_by_year = defaultdict(list)self.batch_size = batch_size  # 分批處理大小except Error as e:print(f"數據庫連接錯誤: {e}")def load_employees_by_year_batch(self):"""分批按入職年份加載員工數據"""offset = 0while True:query = f"""SELECT emp_no, first_name, last_name, gender, hire_date, YEAR(hire_date) as hire_yearFROM employeesORDER BY hire_dateLIMIT {self.batch_size} OFFSET {offset}"""cursor = self.connection.cursor(dictionary=True)cursor.execute(query)rows = cursor.fetchall()cursor.close()if not rows:breakfor row in rows:hire_year = row['hire_year']self.employees_by_year[hire_year].append({'emp_no': row['emp_no'],'name': f"{row['first_name']} {row['last_name']}",'gender': row['gender'],'hire_date': row['hire_date']})offset += self.batch_sizedef get_employees_by_year(self, year=None, max_display=10):"""獲取特定年份入職的員工(限制顯示數量):param year: 年份:param max_display: 最大顯示數量:return: 格式化字符串結果"""if not self.employees_by_year:self.load_employees_by_year_batch()if year:employees = self.employees_by_year.get(year, [])result = f"{year}年入職員工(共{len(employees)}人):\n"for emp in employees[:max_display]:result += f"{emp['emp_no']}: {emp['name']} ({emp['gender']}) - {emp['hire_date']}\n"if len(employees) > max_display:result += f"...(僅顯示前{max_display}條,共{len(employees)}條)"return resultelse:return "請指定具體年份"def analyze_hire_years(self):"""分析每年入職人數統計"""if not self.employees_by_year:self.load_employees_by_year_batch()stats = {year: len(employees) for year, employees in self.employees_by_year.items()}return statsdef visualize_hire_trends(self, start_year=None, end_year=None):"""可視化每年入職人數趨勢(優化大數據處理)"""stats = self.analyze_hire_years()# 篩選年份范圍years = sorted(stats.keys())if start_year:years = [y for y in years if y >= start_year]if end_year:years = [y for y in years if y <= end_year]counts = [stats[y] for y in years]# 創建圖表fig, ax = plt.subplots(figsize=(14, 6))# 使用條形圖更適合離散年份數據bars = ax.bar(years, counts, color='#1f77b4', alpha=0.7)# 設置中文標題和標簽ax.set_title("公司每年入職員工數量趨勢", fontsize=14, pad=20)ax.set_xlabel("入職年份", fontsize=12)ax.set_ylabel("員工數量", fontsize=12)# 優化刻度顯示ax.set_xticks(years)ax.set_xticklabels(years, rotation=45, ha='right')# 添加網格和數據標簽ax.grid(axis='y', linestyle='--', alpha=0.6)for bar in bars:height = bar.get_height()ax.text(bar.get_x() + bar.get_width()/2., height,f'{height:,}', ha='center', va='bottom', fontsize=9)# 自動調整布局plt.tight_layout()return figdef generate_report(self, start_year=None, end_year=None, sample_size=5):"""生成精簡版報告(避免大數據量輸出)"""stats = self.analyze_hire_years()# 篩選年份范圍years = sorted(stats.keys())if start_year:years = [y for y in years if y >= start_year]if end_year:years = [y for y in years if y <= end_year]result = "員工入職年份統計報告\n"result += "="*40 + "\n"for year in years:count = stats[year]employees = self.employees_by_year[year]result += f"\n{year}年: 共{count}人\n"result += "示例員工:\n"# 顯示樣本員工for emp in employees[:sample_size]:result += f"  - {emp['emp_no']}: {emp['name']} ({emp['gender']})\n"if count > sample_size:result += f"  ...(共{count}人)\n"return resultdef close(self):"""關閉數據庫連接"""if hasattr(self, 'connection') and self.connection.is_connected():self.connection.close()# 使用示例
if __name__ == "__main__":# 初始化篩選器filter = EmployeeFilter(host="localhost",database="employees",user="root",password="root")try:# 示例1:獲取特定年份入職員工(限制輸出)print(filter.get_employees_by_year(1986))# 示例2:生成精簡報告print("\n" + filter.generate_report(1985, 1990))# 示例3:可視化1985-2000年趨勢fig = filter.visualize_hire_trends(1985, 2000)plt.show()# 示例4:統計信息stats = filter.analyze_hire_years()print("\n入職人數最多的年份:")peak_year = max(stats.items(), key=lambda x: x[1])print(f"{peak_year[0]}年: {peak_year[1]:,}人")finally:# 確保關閉連接filter.close()1986年入職員工(36150):
89812: Boriana Vingron (F) - 1986-01-01
90916: Eishiro Curless (M) - 1986-01-01
202218: Kristian Bergere (M) - 1986-01-01
213442: Vidar Tibblin (M) - 1986-01-01
214099: Holgard Prenel (F) - 1986-01-01
100711: Kwangyoen Rosca (M) - 1986-01-01
100812: Saniya Lanphier (F) - 1986-01-01
103944: Domenick Dehkordi (M) - 1986-01-01
104083: Basil Matteis (F) - 1986-01-01
104764: Juichirou Munke (M) - 1986-01-01
...(僅顯示前10條,共36150)員工入職年份統計報告
========================================1985:35316人
示例員工:- 110022: Margareta Markovitch (M)- 110085: Ebru Alpin (M)- 110183: Shirish Ossenbruggen (F)- 110303: Krassimir Wegerle (F)- 110511: DeForest Hagimont (M)...(35316)1986:36150人
示例員工:- 89812: Boriana Vingron (F)- 90916: Eishiro Curless (M)- 202218: Kristian Bergere (M)- 213442: Vidar Tibblin (M)- 214099: Holgard Prenel (F)...(36150)1987:33501人
示例員工:- 417048: Subhada Bernardeschi (F)- 401034: Chikako Famili (F)- 422005: Avishai Stentiford (M)- 401863: Ghassan Wolniewicz (F)- 403068: Urs Matzat (M)...(33501)1988:31436人
示例員工:- 475755: Radhakrishnan Coombs (F)- 477365: Heng Siksek (M)- 478116: Debatosh Piveteau (F)- 478374: Hironoby Furudate (F)- 482005: Kwangyoen Dahlbom (M)...(31436)1989:28394人
示例員工:- 207103: Wonhee Byoun (F)- 211368: Alenka Zirintsis (F)- 211528: Kiam Schaar (M)- 100526: Huei Sewelson (M)- 213224: Godehard Demeyer (F)...(28394)1990:25610人
示例員工:- 418290: Remzi Demizu (F)- 419042: Insup Rosar (F)- 419834: Mohit Hiroyama (F)- 421168: Kshitij Falco (F)- 430862: Hugo Uchoa (M)...(25610)入職人數最多的年份:
1986: 36,150

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92231.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92231.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92231.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深度學習圖像預處理:統一輸入圖像尺寸方案

在實際訓練中&#xff0c;最常見也最簡單的做法&#xff0c;就是在送入網絡前把所有圖片「變形」到同一個分辨率&#xff08;比如 256256 或 224224&#xff09;&#xff0c;或者先裁剪&#xff0f;填充成同樣大小。具體而言&#xff0c;可以分成以下幾類方案&#xff1a;一、圖…

pytest-log

問題1&#xff1a;我們在運行測試用例的時候如何記錄測試的log&#xff0c;如何使用&#xff1f;問題2&#xff1a;我寫的函數&#xff0c;為了方便log記錄&#xff0c;但是在pytest運行時&#xff0c;會兼容pytest且不會重復記錄&#xff0c;怎么解決&#xff1f;1、pytest有內…

在安卓源碼中添加自定義jar包給源碼中某些模塊使用

一、具體步驟 1. 準備目錄與 Jar 包 在vendor下 創建新的模塊目錄&#xff0c;放入demo.jar 包&#xff1a; demojar/ # 模塊目錄 ├── Android.bp # 編譯配置文件 └── demo.jar 2. 編寫 Android.bp 配置 Android.bp 示例配置&#xff1a; java_import {…

buntu 22.04 上離線安裝Docker 25.0.5(二)

以下有免費的4090云主機提供ubuntu22.04系統的其他入門實踐操作 地址&#xff1a;星宇科技 | GPU服務器 高性能云主機 云服務器-登錄 相關兌換碼星宇社區---4090算力卡免費體驗、共享開發社區-CSDN博客 兌換碼要是過期了&#xff0c;可以私信我獲取最新兌換碼&#xff01;&a…

初探 Web 環境下的 LLM 安全:攻擊原理與風險邊界

文章目錄前言1 什么是大型語言模型&#xff08;LLM&#xff09;&#xff1f;1.1 LLM的核心特征1.2 LLM在Web場景中的典型應用2 LLM攻擊的核心手段&#xff1a;提示注入與權限濫用3 LLM與API集成的安全隱患&#xff1a;工作流中的漏洞節點3.1 LLM-API集成的典型工作流3.2 工作流…

【新手向】PyTorch常用Tensor shape變換方法

【新手向】PyTorch常用Tensor shape變換方法 前言 B站UP主科研水神大隊長的視頻中介紹了“縫合模塊”大法&#xff0c;其中專門強調了“深度學習 玩的就是shape”。受此啟發&#xff0c;專門整理能夠調整tensor形狀的幾個內置函數&#xff0c;方便以后更好地調整PyTorch代碼中的…

React 18 vs Vue3:狀態管理方案深度對比

?? 背景: React有Redux、Zustand、Jotai等方案 Vue有Pinia、Vuex 4.x 如何選擇適合項目的方案? ?? 核心對比: 維度 React (Redux Toolkit) Vue3 (Pinia) 類型安全 ? 需手動配置TS ? 自動類型推導 代碼量 較多(需寫action) 較少(類似Vuex 5) 響應式原理 不可變數據…

UE5網絡聯機函數

Find Sessions Create Session Join Session Destroy Session Steam是p2p直接聯機 一、steam提供的測試用AppId AppId是steam為每一款游戲所設定的獨有標識&#xff0c;每一款要上架steam的游戲都會擁有獨一無二的AppId。不過為了方便開發者測試&#xff0c;steam提供了游…

Spring Boot 監控:AOP vs Filter vs Java Agent

01前言 在 高并發 微服務 中&#xff0c; 傳統 手動埋點&#xff08;System.currentTimeMillis()&#xff09;就像用體溫計量火箭速度——代碼侵入、重復勞動、維護爆炸。 下文是無侵入、高精度、全鏈路 監控 API 耗時&#xff0c;全程不碰業務代碼的方案&#xff01; 02實戰&…

基于Android的電子記賬本系統

博主介紹&#xff1a;java高級開發&#xff0c;從事互聯網行業多年&#xff0c;熟悉各種主流語言&#xff0c;精通java、python、php、爬蟲、web開發&#xff0c;已經做了多年的畢業設計程序開發&#xff0c;開發過上千套畢業設計程序&#xff0c;沒有什么華麗的語言&#xff0…

7月17日日記

結束了數學建模之后的這兩天一直在緊張的復習&#xff0c;但是說實話效率有點低&#xff0c;因為可能覺得自己找到了兩個小時速成課&#xff0c;覺得無所謂了&#xff0c;所以有點放松了。在宿舍杰哥和林雨城卻一直在復習&#xff0c;感覺他們的微積分和線性代數復習的都比我好…

Linux下SPI設備驅動開發

一.SPI協議介紹1.硬件連接介紹引腳含義&#xff1a;DO(MOSI)&#xff1a;Master Output, Slave Input&#xff0c;SPI主控用來發出數據&#xff0c;SPI從設備用來接收數據。DI(MISO)&#xff1a;Master Input, Slave Output&#xff0c;SPI主控用來發出數據&#xff0c;SPI從設…

用Dify構建氣象智能體:從0到1搭建AI工作流實戰指南

作為一名Agent產品經理,我最近在負責氣象智能體的建設項目。傳統氣象服務面臨三大痛點:數據孤島嚴重(氣象局API、衛星云圖、地面觀測站等多源數據格式不一)、響應鏈路長(從數據采集到預警發布需人工介入多個環節)、交互體驗單一(用戶只能被動接收標準化預警,無法個性化…

Android NDK ffmpeg 音視頻開發實戰

文章目錄接入FFmpeg1.下載FFmpeg 源碼2.編譯FFmpeg.so庫異常處理3.自定義FFmpeg交互so庫創建4.配置CMakeLists.txt5.CMakeLists.txt 環境配置6.Native與Java層調用解碼器準備接入FFmpeg 1.下載FFmpeg 源碼 FFmpeg官網地址 2.編譯FFmpeg.so庫 移動 FFmpeg 源碼文件夾至 Andr…

使用 go-redis-entraid 實現 Entra ID 無密鑰認證

1、依賴與安裝 步驟命令說明安裝&#xff08;或升級&#xff09; go-redis v9.9go get github.com/redis/go-redis/v9latestentraid 必須 ≥ 9.9.0安裝 go-redis-entraidgo get github.com/redis/go-redis-entraid自動拉取 transit 依賴 2、認證方式一覽 方式說明創建 Stream…

window上docker安裝RabbitMQ

1、要進http://localhost:15672管理頁面需要安裝management版本2、搜索鏡像并pull3、啟動鏡像時將端口映射出來4、啟動成功&#xff0c;點擊可查看日志詳情&#xff0c;瀏覽器訪問5、直接使用guest/guest登錄會報錯User can only log in via localhost解決辦法有兩個&#xff1…

異世界歷險之數據結構世界(排序(插入,希爾,堆排))

前言 介紹 插入排序 基本知識&#xff1a; 直接插入排序是一種簡單的插入排序法&#xff0c;其基本思想是&#xff1a; 把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中&#xff0c;直到所有的記錄插入完為止&#xff0c;得到一個新的有序序列 直接插入…

oracle 數據庫中,將幾張表的數據按指定日期范圍實時同步至同一個數據庫的備份表中。

以下是一個Oracle數據庫中實現表數據按指定日期范圍實時同步至備份表的解決方案。這個方案使用存儲過程和觸發器組合實現&#xff1a; 1. 創建備份表結構 首先需要為每張需要備份的表創建對應的備份表&#xff0c;結構與原表相同&#xff1a; -- 為原表創建備份表&#xff08;示…

電腦網絡連接正常,微信、QQ能正常使用,但無法訪問網頁?DNS問題的解決方案和背后原理。

文章目錄1. 問題背景2. 解決方案2.1 手動刷新DNS2.1.1 Windows版本2.1.2 Mac版本2.2 手動設置DNS服務器2.2.1 Windows版2.2.2 Mac版2.3 其他解決方案3. DNS是什么&#xff1f;3.1 詳細解釋DNS3.1.1 A distributed, hierarchical database&#xff08;一個分布式和分層數據庫結構…

【HTML】圖片比例和外部div比例不一致,最大程度占滿

圖片比例和外部div比例不一致&#xff0c;最大程度占滿&#xff0c;并且圖片比例不變 其中1.jpg,2.jpg,1.html在同一目錄 |-----|- 1.jpg|- 2.jpg|- 1.html1.jpg2.jpg<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /&g…