课题四十三:人事管理系统开发(1-2人)
(1) 员工信息管理:员工的姓名、性别、工作岗位、所在部门、学历、婚姻状况、专业、毕业时间、学校、外语情况、职称等基本信息的录入、修改与删除。
(2)企业工作岗位信息和部门信息管理:企业中的工作岗位信息和部门信息的录入、修改与删除(如转出、辞职、辞退、退休) 。
(3)职称信息的管理:所有职称的种类、专业等信息的录入、修改与删除。
(4)职工的档案管理:对职工档案信息的录入、修改与删除。
(4)信息的查询:对各类信息按不同的条件进行查询。
(5)信息的统计:对各类信息按不同的条件进行统计
用mysql 可以吗
使用开源的springboot框架就行了
后端系统搭吗,只是把数据源替换一下,用开源的应用框架试一下。
目的:
1)缓存SQL查询结果。
2)分页和排序通过Redis进行操作,减少数据库的查询次数。
环境:
工具:Redis 4.0.6,Jedis 2.1.0
平台:Java 1.7
数据库:MySql 5.7.17
实现:
1、生成key策略:
目的是确保唯一性,笔者采用 “方法名” + “SQL”,也可以视情况加上时间戳等条件。
2、工具类:
序列化工具。Redis不支持Java将对象直接存储到数据库中,因此需要将Java对象进行序列化,反之从Redis中取出也要反序列化。
public byte[] serialize(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
return baos.toByteArray();
}catch (Exception e) {
throw new CacheException(e);
}
}
public Object unserialize(byte[] bytes) {
if (bytes == null) {
return null;
}
ByteArrayInputStreambais = null;
try {
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}catch (Exception e) {
throw new CacheException(e);
}
}
分页工具类
public class PageData<T> {
/** 数据集合 */
protected List<T> result = Lists.newArrayList();
/** 数据总数 */
protected int totalCount = 0;
/** 总页数 */
protected long pageCount = 0;
/** 每页记录 */
protected int pageSize = 15;
/** 初始当前页 */
protected int pageNo = 1;
}
3、缓存结构设计
缓存数据这里要分3种类型:需要分页的数据、需要分页和排序的数据和普通数据。
3.1普通数据(既不需要分页也不需要排序)
存储到Hash数据中
public void putObject(final Object key,final Object value, final Integer timeout) {
// 全局变量Hash表的ID
finalbyte[] idBytes = id.getBytes();
Jedisjedis = jedisPool.getResource();
jedis.hset(idBytes,key.toString().getBytes(), SerializeUtil.serialize(value));
if(timeout != null && jedis.ttl(idBytes) == -1) {
jedis.expire(idBytes,timeout);
}
}
public Object getObject(final Object key) {
Jedis jedis =jedisPool.getResource();
return SerializeUtil.unserialize(jedis.hget(id.getBytes(),key.toString().getBytes()));
}
3.2有分页需求的数据
MySql中Limit分页是将所有符合条件的数据全部查询出来,再根据Limit的参数进行截取。
Redis中Sorted Set可以很好的完成分页的功能。将查询结果全部存储到缓存中,每次获取分页数据,都由Redis完成。
Sorted Set API:
获得总记录数:zcard(key)
获得指定范围的结果集:zrange(key, beginIndex, endIndex)
缓存结果图解:
(Member记录每行结果,用逗号分隔每一列,分数记录每行结果的索引值。)
/**
* 保存缓存
* @param key 根据策略生成的key
* @param list 查询结果
* @param timeout 缓存过期时间
*/
public void saveCache(final String key, List<?> list, final Integer timeout) {
if (list.size() > 0) {
Jedis redis = jedisPool.getResource();
Pipeline pipeline = redis.pipelined();
// 开启事务
pipeline.multi();
for (Integer i = 0; i < list.size(); i++) {
Object[] dataForRow = (Object[])list.get(i);
String setValue = "";
for (Integer j = 0; j < dataForRow.length; j++) {
if (dataForRow[j] == null) {
dataForRow[j] = " ";
}
setValue += dataForRow[j].toString() + ",";
}
pipeline.zadd(key, (double)i, setValue);
}
// 设置过期时间
pipeline.expire(key, timeout);
// 提交事务
pipeline.exec();
pipeline.sync();
jedisPool.returnResource(redis);
}
}
/**
* 从缓存读取数据
* @param pageData 分页工具类
* @param key
* @return
*/
public PageData<Object[]> findPageDataByCache(PageData<Object[]> pageData, final String key) {
Jedis redis = jedisPool.getResource();
List<Object[]> cacheList = new ArrayList<Object[]>();
if (key!= null && !"".equals(key)) {
// 获得总记录数
Long totalCount = redis.zcard(key);
if (totalCount > 0) {
// 计算分页
Integer beginIndex = ((pageData.getPageNo() - 1) * pageData.getPageSize());
Integer endIndex = (beginIndex + pageData.getPageSize() - 1);
if (pageData.getTotalCount() == 0) {
// 保存总记录数
pageData.setTotalCount(totalCount.intValue());
}
// Sorted Set返回结果集封装为LinkedHashSet
Set<String> cacheDataForRow = redis.zrange(key, beginIndex, endIndex);
for (String dataUnitArray : cacheDataForRow) {
Object[] dataUnit = (Object[])dataUnitArray.split(",");
cacheList.add(dataUnit);
}
pageData.setResult(cacheList);
}
}
jedisPool.returnResource(redis);
return pageData;
}
3.3有分页和排序需求的数据
设计原理:
根据存储分页数据的基础上,每一行生成一条Hash结构的数据。
排序需要建立列名和对应列的数据的对应关系,即获得排序字段时,能找到该列的所有数据才能进行比较。
Hash数据的key根据Sorted Set的分数(即每行数据的索引值) + Key生成,这样做是为了根据每行的索引值找到该set生成的所有的Hash数据。
根据某列进行排序,得到排序后行索引值的集合,再根据索引值取出Sorted Set中的数据。使用Redis的Sort命令实现此需求。
图解:
现在对row0做降序处理,row0中的3条数据的值是4,1,7,因此我们希望得到的索引集合是2,1,0。
存储每一行列名和值的Hash数据
Sorted Set数据
indexList存储是原Sorted Set中的索引号,即0,1,2
Sort命令得到排序后的索引,通过Hash数据的row0列进行排序,返回indexList中的值。
其中BY *key1->row0:
*通配符是指从indexList中取出的数值,key1是缓存数据的key;*key1相当于生成0key1、1key1、2key1。
->row0是指以“*key1”的Hash数据中取”row0”列进行比较、排序。
SORT indexList BY *key1->row0 DESC : 以0key1、1key1、2key1中field是row0的值组合成的新key,并按照新key中的内容进行排序,返回排序后的indexList。
注意:若排序字段是字符串,需要加ALPHA参数。Sort命令的详细使用方法可查看官网文档。
有了排序后的索引值集合,就可以取出排序后的结果集。
代码部分:
注意:根据SQL生成Key时不要将order参数写入,会导致每次查询排序时生成的Key不相同,将order作为参数交给Redis进行操作。
/**
* 生成排序索引key
*/
public static synchronized String createSortedListKey(String conditionId, String sortName, String sortOrder) {
String sortedListKey = conditionId + ":" + sortName + ":" + sortOrder;
return sortedListKey;
}
/**
* 生成排序索引key
*/
public static synchronized String createSortedListKey(String conditionId, String sortName, String sortOrder) {
String sortedListKey = conditionId + ":" + sortName + ":" + sortOrder;
return sortedListKey;
}
/**
* 保存缓存(排序)
* @param list
* @param rowNameList 列名集合
* @param timeout
*/
public void saveCacheDataWithSort(List<?> list, List<String> rowNameList , final String key, final Integer timeout) {
if (list.size() > 0) {
Jedis redis = jedisPool.getResource();
Pipeline pipeline = redis.pipelined();
// 开启事务
pipeline.multi();
for (Integer i = 0; i < list.size(); i++) {
Object[] dataForRow = (Object[])list.get(i);
String setValue = "";
Map<String, String> resultWithRowMap = new HashMap<String, String>();
for (Integer j = 0; j < dataForRow.length; j++) {
if (dataForRow[j] == null) {
dataForRow[j] = " ";
}
resultWithRowMap.put(rowNameList.get(j), dataForRow[j].toString());
setValue += dataForRow[j].toString() + ",";
}
// setValueMap.put((double)i, setValue);
pipeline.zadd(key, (double)i, setValue);
// 将每一行数据(含列名)保存hash数据
pipeline.hmset(i + key, resultWithRowMap);
pipeline.expire(i + key, timeout);
}
// 设置过期时间
pipeline.expire(key, timeout);
// 提交事务
pipeline.exec();
pipeline.sync();
jedisPool.returnResource(redis);
}
}
/**
* 读取缓存返回pageData分页对象(含排序)
* @param pageData
* @param sortName
* @param sortOrder
* @param sortIsString 排序字段是否字符
* @return
*/
public PageData<Object[]> findPageDataByCacheWithSort(PageData<Object[]> pageData, final String key, String sortName, String sortOrder, Boolean sortIsString) {
// 生成排序索引key,缓存Sort命令排序后生成的索引集合
String sortedListKey = CacheUtil.createSortedListKey(key, sortName, sortOrder);
Jedis redis = jedisPool.getResource();
List<Object[]> cacheList = new ArrayList<Object[]>();
if (key!= null && !"".equals(key)) {
Integer totalCount = redis.zcard(key).intValue();
if (totalCount > 0) {
// 查看是是否有该排序的缓存
byte[] bytes = redis.get(sortedListKey.getBytes());
List<?> resultIndexList = SerializeUtil.unserializeList(bytes);
if (resultIndexList == null || resultIndexList.isEmpty()) {
// 根据缓存数据的长度,创建用于存储每行数据索引的临时List
String uuId = UUID.randomUUID().toString().replaceAll("-", "");
Pipeline pipeline = redis.pipelined();
for (Integer i = 0; i < totalCount; i++) {
pipeline.rpush(uuId, i.toString());
}
pipeline.sync();
// 排序参数对象
SortingParams sortingParams = new SortingParams();
// *是通配符,此处zset中所有分数
// *zsetId取出所有行数据的hash数据
// ->sortName指以hash数据中的sortName字段进行排序
sortingParams.by("*" + key + "->" + sortName);
if ("asc".equals(sortOrder)) {
sortingParams.asc();
} else {
sortingParams.desc();
}
if (sortIsString) {
// 根据字符进行排序
sortingParams.alpha();
}
// 获得排序后的索引集合
resultIndexList = redis.sort(uuId, sortingParams);
// 删除key = uuId的临时List
redis.ltrim(uuId, 1, 0);
// 将排序后的索引存入缓存,过期时间与当前报表同步
redis.set(sortedListKey.getBytes(), SerializeUtil.serializeList(resultIndexList));
redis.expire(sortedListKey, redis.ttl(key).intValue());
}
// 根据pageData属性计算分页
Integer beginIndex = ((pageData.getPageNo() - 1) * pageData.getPageSize());
Integer endIndex = (beginIndex + pageData.getPageSize());
if (pageData.getTotalCount() == 0) {
// 保存总记录数
pageData.setTotalCount(totalCount);
}
// 若取值范围大于实际结果集长度,则endIndex取实际结果集长度
endIndex = resultIndexList.size() < endIndex ? resultIndexList.size() : endIndex;
// 根据排序索引从缓存中逐条读取
Pipeline pipeline2 = redis.pipelined();
List<Response<Set<String>>> responseSetList = new ArrayList<Response<Set<String>>>();
for (Integer j = beginIndex; j < endIndex; j++) {
String index = resultIndexList.get(j).toString();
Response<Set<String>> responseSet = pipeline2.zrangeByScore(key, index, index);
responseSetList.add(responseSet);
}
pipeline2.sync();
for (Response<Set<String>> response : responseSetList) {
Set<String> cacheDataSet = response.get();
Iterator<String> it = cacheDataSet.iterator();
if (it.hasNext()) {
Object[] dataUnit = (Object[])it.next().split(",");
cacheList.add(dataUnit);
}
}
pageData.setResult(cacheList);
}
}
jedisPool.returnResource(redis);
return pageData;
}
第一次写博客,内容很粗糙,仅供参考;欢迎各种建议、指正和交流。
邮箱:594187062@qq.com
基本实现,如果帮助欢迎采纳,来自GPT
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import javax.swing.*;
public class EmployeeManagementSystem extends JFrame implements ActionListener {
private JLabel nameLabel, genderLabel, positionLabel, departmentLabel, educationLabel, maritalStatusLabel, majorLabel, graduationLabel, schoolLabel, languageLabel, titleLabel;
private JTextField nameField, positionField, departmentField, majorField, graduationField, schoolField, languageField;
private JComboBox<String> genderBox, educationBox, maritalStatusBox, titleBox;
private JButton addButton, updateButton, deleteButton, searchButton;
private JTable table;
private DefaultTableModel model;
private Connection conn;
private PreparedStatement pstmt;
private ResultSet rs;
public EmployeeManagementSystem() {
super("员工信息管理系统");
// 基本信息标签和文本框
nameLabel = new JLabel("姓名:");
genderLabel = new JLabel("性别:");
positionLabel = new JLabel("工作岗位:");
departmentLabel = new JLabel("所在部门:");
educationLabel = new JLabel("学历:");
maritalStatusLabel = new JLabel("婚姻状况:");
majorLabel = new JLabel("专业:");
graduationLabel = new JLabel("毕业时间:");
schoolLabel = new JLabel("学校:");
languageLabel = new JLabel("外语情况:");
titleLabel = new JLabel("职称:");
nameField = new JTextField(10);
positionField = new JTextField(10);
departmentField = new JTextField(10);
majorField = new JTextField(10);
graduationField = new JTextField(10);
schoolField = new JTextField(10);
languageField = new JTextField(10);
genderBox = new JComboBox<String>(new String[] { "男", "女" });
educationBox = new JComboBox<String>(new String[] { "博士", "硕士", "本科", "专科", "高中", "初中", "小学" });
maritalStatusBox = new JComboBox<String>(new String[] { "已婚", "未婚" });
titleBox = new JComboBox<String>(new String[] { "初级工程师", "中级工程师", "高级工程师", "总工程师" });
// 操作按钮
addButton = new JButton("添加");
updateButton = new JButton("修改");
deleteButton = new JButton("删除");
searchButton = new JButton("查询");
addButton.addActionListener(this);
updateButton.addActionListener(this);
deleteButton.addActionListener(this);
searchButton.addActionListener(this);
// 表格
model = new DefaultTableModel();
table = new JTable(model);
model.addColumn("姓名");
model.addColumn("性别");
model.addColumn("工作岗位");
model.addColumn("所在部门");
model.addColumn("学历");
model.addColumn("婚姻状况");
model.addColumn("专业");
model.addColumn("毕业时间");
model.addColumn("学校");
model.addColumn("外语情况");
model.addColumn("职称");
JScrollPane scrollPane = new JScrollPane(table);
// 布局
JPanel panel1 = new JPanel(new GridLayout(11, 2));
panel1.add(nameLabel);
panel1.add(nameField);
panel1.add(genderLabel);
panel1.add(genderBox);
panel1.add(positionLabel);
panel1.add(positionField);
panel1.add(departmentLabel);
panel1.add(departmentField);
panel1.add(educationLabel);
panel1.add(educationBox);
panel1.add(maritalStatusLabel);
panel1.add(maritalStatusBox);
panel1.add(majorLabel);
panel1.add(majorField);
panel1.add(graduationLabel);
panel1.add(graduationField);
panel1.add(schoolLabel);
panel1.add(schoolField);
panel1.add(languageLabel);
panel1.add(languageField);
panel1.add(titleLabel);
panel1.add(titleBox);
JPanel panel2 = new JPanel(new FlowLayout());
panel2.add(addButton);
panel2.add(updateButton);
panel2.add(deleteButton);
panel2.add(searchButton);
setLayout(new BorderLayout());
add(panel1, BorderLayout.NORTH);
add(scrollPane, BorderLayout.CENTER);
add(panel2, BorderLayout.SOUTH);
setSize(800, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
try {
// 连接数据库
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String url = "jdbc:sqlserver://localhost:1433;databaseName=employee_db";
String user = "sa";
String password = "123456";
conn = DriverManager.getConnection(url, user, password);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == addButton) {
addEmployee();
} else if (e.getSource() == updateButton) {
updateEmployee();
} else if (e.getSource() == deleteButton) {
deleteEmployee();
} else if (e.getSource() == searchButton) {
searchEmployee();
}
}
private void addEmployee() {
String name = nameField.getText().trim();
String gender = genderBox.getSelectedItem().toString();
String position = positionField.getText().trim();
String department = departmentField.getText().trim();
String education = educationBox.getSelectedItem().toString();
String maritalStatus = maritalStatusBox.getSelectedItem().toString();
String major = majorField.getText().trim();
String graduation = graduationField.getText().trim();
String school = schoolField.getText().trim();
String language = languageField.getText().trim();
String title = titleBox.getSelectedItem().toString();
if (name.equals("")) {
JOptionPane.showMessageDialog(this, "请输入姓名", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
try {
// 添加员工信息
pstmt = conn.prepareStatement("INSERT INTO employee_info VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
pstmt.setString(1, name);
pstmt.setString(2, gender);
pstmt.setString(3, position);
pstmt.setString(4, department);
pstmt.setString(5, education);
pstmt.setString(6, maritalStatus);
pstmt.setString(7, major);
pstmt.setString(8, graduation);
pstmt.setString(9, school);
pstmt.setString(10, language);
pstmt.setString(11, title);
pstmt.executeUpdate();
JOptionPane.showMessageDialog(this, "添加成功", "提示", JOptionPane.INFORMATION_MESSAGE);
clearFields();
refreshTable();
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this, "添加失败", "错误", JOptionPane.ERROR_MESSAGE);
}
}
private void updateEmployee() {
int row = table.getSelectedRow();
if (row == -1) {
JOptionPane.showMessageDialog(this, "请选择要修改的员工信息", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
String name = nameField.getText().trim();
String gender = genderBox.getSelectedItem().toString();
String position = positionField.getText().trim();
String department = departmentField.getText().trim();
String education = educationBox.getSelectedItem().toString();
String maritalStatus = maritalStatusBox.getSelectedItem().toString();
String major = majorField.getText().trim();
String graduation = graduationField.getText().trim();
String school = schoolField.getText().trim();
String language = languageField.getText().trim();
String title = titleBox.getSelectedItem().toString();
if (name.equals("")) {
JOptionPane.showMessageDialog(this, "请输入姓名", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
try {
// 更新员工信息
pstmt = conn.prepareStatement("UPDATE employee_info SET gender=?, position=?, department=?, education=?, marital_status=?, major=?, graduation=?, school=?, language=?, title=? WHERE name=?");
pstmt.setString(1, gender);
pstmt.setString(2, position);
pstmt.setString(3, department);
pstmt.setString(4, education);
pstmt.setString(5, maritalStatus);
pstmt.setString(6, major);
pstmt.setString(7, graduation);
pstmt.setString(8, school);
pstmt.setString(9, language);
pstmt.setString(10, title);
pstmt.setString(11, name);
pstmt.executeUpdate();
JOptionPane.showMessageDialog(this, "修改成功", "提示", JOptionPane.INFORMATION_MESSAGE);
clearFields();
refreshTable();
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this, "修改失败", "错误", JOptionPane.ERROR_MESSAGE);
}
}
private void deleteEmployee() {
int row = table.getSelectedRow();
if (row == -1) {
JOptionPane.showMessageDialog(this, "请选择要删除的员工信息", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
String name = (String) model.getValueAt(row, 0);
try {
// 删除员工信息
pstmt = conn.prepareStatement("DELETE FROM employee_info WHERE name=?");
pstmt.setString(1, name);
pstmt.executeUpdate();
JOptionPane.showMessageDialog(this, "删除成功", "提示", JOptionPane.INFORMATION_MESSAGE);
clearFields();
refreshTable();
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this, "删除失败", "错误", JOptionPane.ERROR_MESSAGE);
}
}
private void searchEmployee() {
String name = nameField.getText().trim();
String gender = genderBox.getSelectedItem().toString();
String position = positionField.getText().trim();
String department = departmentField.getText().trim();
String education = educationBox.getSelectedItem().toString();
String maritalStatus = maritalStatusBox.getSelectedItem().toString();
String major = majorField.getText().trim();
String graduation = graduationField.getText().trim();
String school = schoolField.getText().trim();
String language = languageField.getText().trim();
String title = titleBox.getSelectedItem().toString();
try {
// 查询员工信息
String sql = "SELECT * FROM employee_info WHERE 1=1";
if (!name.equals("")) {
sql += " AND name='" + name + "'";
}
if (!gender.equals("")) {
sql += " AND gender='" + gender + "'";
}
if (!position.equals("")) {
sql += " AND position='" + position + "'";
}
if (!department.equals("")) {
sql += " AND department='" + department + "'";
}
if (!education.equals("")) {
sql += " AND education='" + education + "'";
}
if (!maritalStatus.equals("")) {
sql += " AND marital_status='" + maritalStatus + "'";
}
if (!major.equals("")) {
sql += " AND major='" + major + "'";
}
if (!graduation.equals("")) {
sql += " AND graduation='" + graduation + "'";
}
if (!school.equals("")) {
sql += " AND school='" + school + "'";
}
if (!language.equals("")) {
sql += " AND language='" + language + "'";
}
if (!title.equals("")) {
sql += " AND title='" + title + "'";
}
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
model.setRowCount(0);
while (rs.next()) {
String[] row = new String[11];
row[0] = rs.getString("name");
row[1] = rs.getString("gender");
row[2] = rs.getString("position");
row[3] = rs.getString("department");
row[4] = rs.getString("education");
row[5] = rs.getString("marital_status");
row[6] = rs.getString("major");
row[7] = rs.getString("graduation");
row[8] = rs.getString("school");
row[9] = rs.getString("language");
row[10] = rs.getString("title");
model.addRow(row);
}
rs.close();
pstmt.close();
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this, "查询失败", "错误", JOptionPane.ERROR_MESSAGE);
}
}
private void clearFields() {
nameField.setText("");
genderBox.setSelectedIndex(0);
positionField.setText("");
departmentField.setText("");
educationBox.setSelectedIndex(0);
maritalStatusBox.setSelectedIndex(0);
majorField.setText("");
graduationField.setText("");
schoolField.setText("");
languageField.setText("");
titleBox.setSelectedIndex(0);
}
private void refreshTable() {
try {
// 刷新表格数据
pstmt = conn.prepareStatement("SELECT * FROM employee_info");
rs = pstmt.executeQuery();
model.setRowCount(0);
while (rs.next()) {
String[] row = new String[11];
row[0] = rs.getString("name");
row[1] = rs.getString("gender");
row[2] = rs.getString("position");
row[3] = rs.getString("department");
row[4] = rs.getString("education");
row[5] = rs.getString("marital_status");
row[6] = rs.getString("major");
row[7] = rs.getString("graduation");
row[8] = rs.getString("school");
row[9] = rs.getString("language");
row[10] = rs.getString("title");
model.addRow(row);
}
rs.close();
pstmt.close();
} catch (Exception ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(this, "刷新失败", "错误", JOptionPane.ERROR_MESSAGE);
}
}
public static void main(String[] args) {
new EmployeeManagementSystem();
}
}
##对应的sql代码
CREATE TABLE employee_info (
name VARCHAR(50) PRIMARY KEY,
gender VARCHAR(10),
position VARCHAR(50),
department VARCHAR(50),
education VARCHAR(50),
marital_status VARCHAR(10),
major VARCHAR(50),
graduation VARCHAR(50),
school VARCHAR(50),
language VARCHAR(50),
title VARCHAR(50)
);