代码优化
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
-- OnboardX 部门模块独立维护及层级关联迁移脚本
|
||||
-- 适用数据库:MySQL 8.0+
|
||||
-- 包含:
|
||||
-- 1. 新建 ob_department 表
|
||||
-- 2. 在 ob_position / ob_onboarding_task / ob_employee 中补充 DepartmentId 字段
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- 1. 新建入职业务部门表
|
||||
CREATE TABLE IF NOT EXISTS `ob_department` (
|
||||
`Id` BIGINT NOT NULL COMMENT '主键',
|
||||
`CompanyId` BIGINT NOT NULL COMMENT '所属业务公司Id',
|
||||
`DepartmentCode` VARCHAR(50) NOT NULL COMMENT '部门编码',
|
||||
`DepartmentName` VARCHAR(200) NOT NULL COMMENT '部门名称',
|
||||
`SortCode` INT NOT NULL DEFAULT 99 COMMENT '显示排序',
|
||||
`Remark` VARCHAR(500) NULL COMMENT '部门说明',
|
||||
`ExtJson` LONGTEXT NULL COMMENT '扩展信息',
|
||||
`Status` VARCHAR(20) NULL DEFAULT 'enable' COMMENT '启用状态',
|
||||
`CreateTime` DATETIME(3) NULL COMMENT '创建时间',
|
||||
`UpdateTime` DATETIME(3) NULL COMMENT '更新时间',
|
||||
`CreateUserId` BIGINT NULL COMMENT '创建者Id',
|
||||
`UpdateUserId` BIGINT NULL COMMENT '修改者Id',
|
||||
`CreateUser` VARCHAR(200) NULL COMMENT '创建人',
|
||||
`UpdateUser` VARCHAR(200) NULL COMMENT '更新人',
|
||||
`IsDelete` TINYINT(1) NULL DEFAULT 0 COMMENT '软删除',
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `uk_ob_department_company_code` (`CompanyId`, `DepartmentCode`),
|
||||
KEY `idx_ob_department_company_status` (`CompanyId`, `Status`, `IsDelete`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='入职业务部门';
|
||||
|
||||
-- 2. 定义安全补列存储过程(防重复执行)
|
||||
DROP PROCEDURE IF EXISTS `ob_add_column_if_missing`;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE `ob_add_column_if_missing`(
|
||||
IN p_table_name VARCHAR(128),
|
||||
IN p_column_name VARCHAR(128),
|
||||
IN p_column_definition VARCHAR(1000)
|
||||
)
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = p_table_name
|
||||
AND COLUMN_NAME = p_column_name
|
||||
) THEN
|
||||
SET @ddl = CONCAT(
|
||||
'ALTER TABLE `', p_table_name, '` ADD COLUMN `',
|
||||
p_column_name, '` ', p_column_definition
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
-- 3. 在岗位表中新增 DepartmentId 字段
|
||||
CALL `ob_add_column_if_missing`(
|
||||
'ob_position',
|
||||
'DepartmentId',
|
||||
'BIGINT NULL COMMENT ''所属部门Id'' AFTER `CompanyId`'
|
||||
);
|
||||
|
||||
-- 4. 在入职任务表中新增 DepartmentId 字段
|
||||
CALL `ob_add_column_if_missing`(
|
||||
'ob_onboarding_task',
|
||||
'DepartmentId',
|
||||
'BIGINT NULL COMMENT ''所属部门Id'' AFTER `CompanyId`'
|
||||
);
|
||||
|
||||
-- 5. 在正式员工档案表中新增 DepartmentId 字段
|
||||
CALL `ob_add_column_if_missing`(
|
||||
'ob_employee',
|
||||
'DepartmentId',
|
||||
'BIGINT NULL COMMENT ''所属部门Id'' AFTER `CompanyId`'
|
||||
);
|
||||
|
||||
-- 清理临时存储过程
|
||||
DROP PROCEDURE IF EXISTS `ob_add_column_if_missing`;
|
||||
@@ -0,0 +1,343 @@
|
||||
-- OnboardX 公司、部门、岗位、合同模板及入职模板层级升级脚本
|
||||
-- 适用数据库:MySQL 8.0+
|
||||
-- 说明:
|
||||
-- 1. 可重复执行,不会覆盖已经人工维护的归属数据。
|
||||
-- 2. 仅对能够从现有岗位/入职模板关系中唯一确定的数据执行安全回填。
|
||||
-- 3. 脚本末尾会输出仍需人工处理的数据,请先处理完再启用相关模板。
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
DROP PROCEDURE IF EXISTS `ob_scope_add_column_if_missing`;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE `ob_scope_add_column_if_missing`(
|
||||
IN p_table_name VARCHAR(128),
|
||||
IN p_column_name VARCHAR(128),
|
||||
IN p_column_definition VARCHAR(1000)
|
||||
)
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = p_table_name
|
||||
AND COLUMN_NAME = p_column_name
|
||||
) THEN
|
||||
SET @ddl = CONCAT(
|
||||
'ALTER TABLE `', p_table_name, '` ADD COLUMN `',
|
||||
p_column_name, '` ', p_column_definition
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP PROCEDURE IF EXISTS `ob_scope_add_index_if_missing`;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE `ob_scope_add_index_if_missing`(
|
||||
IN p_table_name VARCHAR(128),
|
||||
IN p_index_name VARCHAR(128),
|
||||
IN p_index_definition VARCHAR(1000)
|
||||
)
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = p_table_name
|
||||
AND INDEX_NAME = p_index_name
|
||||
) THEN
|
||||
SET @ddl = CONCAT(
|
||||
'ALTER TABLE `', p_table_name, '` ADD ', p_index_definition
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
DROP PROCEDURE IF EXISTS `ob_scope_add_unique_index_if_clean`;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE `ob_scope_add_unique_index_if_clean`(
|
||||
IN p_table_name VARCHAR(128),
|
||||
IN p_column_name VARCHAR(128),
|
||||
IN p_index_name VARCHAR(128)
|
||||
)
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = p_table_name
|
||||
AND INDEX_NAME = p_index_name
|
||||
) THEN
|
||||
SET @duplicate_count = 0;
|
||||
SET @check_sql = CONCAT(
|
||||
'SELECT COUNT(*) INTO @duplicate_count FROM (',
|
||||
'SELECT `', p_column_name, '` FROM `', p_table_name, '` ',
|
||||
'WHERE `', p_column_name, '` IS NOT NULL ',
|
||||
'AND LENGTH(TRIM(`', p_column_name, '`)) > 0 ',
|
||||
'GROUP BY `', p_column_name, '` HAVING COUNT(*) > 1',
|
||||
') duplicated_values'
|
||||
);
|
||||
PREPARE stmt FROM @check_sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
IF @duplicate_count = 0 THEN
|
||||
SET @ddl = CONCAT(
|
||||
'ALTER TABLE `', p_table_name, '` ADD UNIQUE INDEX `',
|
||||
p_index_name, '` (`', p_column_name, '`)'
|
||||
);
|
||||
PREPARE stmt FROM @ddl;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
END IF;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
-- 入职模板增加所属部门。
|
||||
CALL `ob_scope_add_column_if_missing`(
|
||||
'ob_onboarding_template',
|
||||
'DepartmentId',
|
||||
'BIGINT NULL COMMENT ''所属部门Id'' AFTER `CompanyId`'
|
||||
);
|
||||
|
||||
-- 合同模板增加所属公司和部门。暂时允许 NULL,以兼容待人工归类的历史模板。
|
||||
CALL `ob_scope_add_column_if_missing`(
|
||||
'ob_contract_template',
|
||||
'CompanyId',
|
||||
'BIGINT NULL COMMENT ''所属公司Id'' AFTER `Id`'
|
||||
);
|
||||
CALL `ob_scope_add_column_if_missing`(
|
||||
'ob_contract_template',
|
||||
'DepartmentId',
|
||||
'BIGINT NULL COMMENT ''所属部门Id'' AFTER `CompanyId`'
|
||||
);
|
||||
|
||||
-- 兼容尚未执行上一版部门迁移的数据库,重复调用不会新增重复字段。
|
||||
CALL `ob_scope_add_column_if_missing`(
|
||||
'ob_position',
|
||||
'DepartmentId',
|
||||
'BIGINT NULL COMMENT ''所属部门Id'' AFTER `CompanyId`'
|
||||
);
|
||||
CALL `ob_scope_add_column_if_missing`(
|
||||
'ob_onboarding_task',
|
||||
'DepartmentId',
|
||||
'BIGINT NULL COMMENT ''所属部门Id'' AFTER `CompanyId`'
|
||||
);
|
||||
CALL `ob_scope_add_column_if_missing`(
|
||||
'ob_employee',
|
||||
'DepartmentId',
|
||||
'BIGINT NULL COMMENT ''所属部门Id'' AFTER `CompanyId`'
|
||||
);
|
||||
|
||||
-- 合同模板与岗位为多对多关系,一份通用合同可同时适用于多个岗位。
|
||||
CREATE TABLE IF NOT EXISTS `ob_contract_template_position` (
|
||||
`Id` BIGINT NOT NULL COMMENT '主键',
|
||||
`ContractTemplateId` BIGINT NOT NULL COMMENT '合同模板Id',
|
||||
`PositionId` BIGINT NOT NULL COMMENT '适用岗位Id',
|
||||
`ExtJson` LONGTEXT NULL COMMENT '扩展信息',
|
||||
`Status` VARCHAR(20) NULL DEFAULT 'enable' COMMENT '启用状态',
|
||||
`CreateTime` DATETIME(3) NULL COMMENT '创建时间',
|
||||
`UpdateTime` DATETIME(3) NULL COMMENT '更新时间',
|
||||
`CreateUserId` BIGINT NULL COMMENT '创建者Id',
|
||||
`UpdateUserId` BIGINT NULL COMMENT '修改者Id',
|
||||
`CreateUser` VARCHAR(200) NULL COMMENT '创建人',
|
||||
`UpdateUser` VARCHAR(200) NULL COMMENT '更新人',
|
||||
`IsDelete` TINYINT(1) NULL DEFAULT 0 COMMENT '软删除',
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `uk_ob_contract_template_position` (`ContractTemplateId`, `PositionId`),
|
||||
KEY `idx_ob_contract_template_position_position` (`PositionId`, `ContractTemplateId`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='合同模板适用岗位';
|
||||
|
||||
CALL `ob_scope_add_index_if_missing`(
|
||||
'ob_position',
|
||||
'idx_ob_position_department_status',
|
||||
'INDEX `idx_ob_position_department_status` (`DepartmentId`, `Status`, `IsDelete`)'
|
||||
);
|
||||
CALL `ob_scope_add_index_if_missing`(
|
||||
'ob_onboarding_template',
|
||||
'idx_ob_onboarding_template_scope',
|
||||
'INDEX `idx_ob_onboarding_template_scope` (`CompanyId`, `DepartmentId`, `Status`, `IsDelete`)'
|
||||
);
|
||||
CALL `ob_scope_add_index_if_missing`(
|
||||
'ob_contract_template',
|
||||
'idx_ob_contract_template_scope',
|
||||
'INDEX `idx_ob_contract_template_scope` (`CompanyId`, `DepartmentId`, `Status`, `IsDelete`)'
|
||||
);
|
||||
CALL `ob_scope_add_index_if_missing`(
|
||||
'ob_onboarding_task',
|
||||
'idx_ob_onboarding_task_department',
|
||||
'INDEX `idx_ob_onboarding_task_department` (`DepartmentId`, `TaskStatus`, `IsDelete`)'
|
||||
);
|
||||
CALL `ob_scope_add_index_if_missing`(
|
||||
'ob_employee',
|
||||
'idx_ob_employee_department',
|
||||
'INDEX `idx_ob_employee_department` (`DepartmentId`, `IsDelete`)'
|
||||
);
|
||||
|
||||
-- 身份证号和手机号是正式员工防重复的数据库最终防线。
|
||||
-- 若历史数据已经重复,本次会安全跳过建索引,并由脚本末尾查询列出冲突数据。
|
||||
CALL `ob_scope_add_unique_index_if_clean`(
|
||||
'ob_employee',
|
||||
'IdCardNumber',
|
||||
'uk_ob_employee_id_card'
|
||||
);
|
||||
CALL `ob_scope_add_unique_index_if_clean`(
|
||||
'ob_employee',
|
||||
'Phone',
|
||||
'uk_ob_employee_phone'
|
||||
);
|
||||
|
||||
-- 安全回填入职模板部门:只有全部适用岗位均属于同一个非空部门时才回填。
|
||||
UPDATE `ob_onboarding_template` template
|
||||
INNER JOIN (
|
||||
SELECT
|
||||
relation.`OnboardingTemplateId`,
|
||||
MIN(position.`DepartmentId`) AS `DepartmentId`
|
||||
FROM `ob_onboarding_template_position` relation
|
||||
INNER JOIN `ob_position` position ON position.`Id` = relation.`PositionId`
|
||||
WHERE COALESCE(relation.`IsDelete`, 0) = 0
|
||||
AND COALESCE(position.`IsDelete`, 0) = 0
|
||||
GROUP BY relation.`OnboardingTemplateId`
|
||||
HAVING COUNT(*) > 0
|
||||
AND COUNT(DISTINCT position.`DepartmentId`) = 1
|
||||
AND SUM(position.`DepartmentId` IS NULL) = 0
|
||||
) source ON source.`OnboardingTemplateId` = template.`Id`
|
||||
SET template.`DepartmentId` = source.`DepartmentId`
|
||||
WHERE template.`DepartmentId` IS NULL;
|
||||
|
||||
-- 安全回填合同模板公司、部门:只有历史引用的入职模板归属完全一致时才回填。
|
||||
UPDATE `ob_contract_template` contract_template
|
||||
INNER JOIN (
|
||||
SELECT
|
||||
relation.`ContractTemplateId`,
|
||||
MIN(template.`CompanyId`) AS `CompanyId`,
|
||||
MIN(template.`DepartmentId`) AS `DepartmentId`
|
||||
FROM `ob_onboarding_template_contract` relation
|
||||
INNER JOIN `ob_onboarding_template` template
|
||||
ON template.`Id` = relation.`OnboardingTemplateId`
|
||||
WHERE COALESCE(relation.`IsDelete`, 0) = 0
|
||||
AND COALESCE(template.`IsDelete`, 0) = 0
|
||||
GROUP BY relation.`ContractTemplateId`
|
||||
HAVING COUNT(DISTINCT template.`CompanyId`) = 1
|
||||
AND COUNT(DISTINCT template.`DepartmentId`) = 1
|
||||
AND SUM(template.`DepartmentId` IS NULL) = 0
|
||||
) source ON source.`ContractTemplateId` = contract_template.`Id`
|
||||
SET contract_template.`CompanyId` = COALESCE(contract_template.`CompanyId`, source.`CompanyId`),
|
||||
contract_template.`DepartmentId` = COALESCE(contract_template.`DepartmentId`, source.`DepartmentId`)
|
||||
WHERE contract_template.`CompanyId` IS NULL
|
||||
OR contract_template.`DepartmentId` IS NULL;
|
||||
|
||||
-- 根据历史入职模板关系,回填合同模板已经实际使用过的岗位范围。
|
||||
INSERT IGNORE INTO `ob_contract_template_position` (
|
||||
`Id`,
|
||||
`ContractTemplateId`,
|
||||
`PositionId`,
|
||||
`Status`,
|
||||
`CreateTime`,
|
||||
`IsDelete`
|
||||
)
|
||||
SELECT DISTINCT
|
||||
CAST(CONV(SUBSTRING(MD5(CONCAT(
|
||||
'obctp:', contract_relation.`ContractTemplateId`, ':', position_relation.`PositionId`
|
||||
)), 1, 15), 16, 10) AS UNSIGNED) AS `Id`,
|
||||
contract_relation.`ContractTemplateId`,
|
||||
position_relation.`PositionId`,
|
||||
'enable',
|
||||
NOW(3),
|
||||
0
|
||||
FROM `ob_onboarding_template_contract` contract_relation
|
||||
INNER JOIN `ob_onboarding_template_position` position_relation
|
||||
ON position_relation.`OnboardingTemplateId` = contract_relation.`OnboardingTemplateId`
|
||||
INNER JOIN `ob_contract_template` contract_template
|
||||
ON contract_template.`Id` = contract_relation.`ContractTemplateId`
|
||||
INNER JOIN `ob_position` position
|
||||
ON position.`Id` = position_relation.`PositionId`
|
||||
WHERE COALESCE(contract_relation.`IsDelete`, 0) = 0
|
||||
AND COALESCE(position_relation.`IsDelete`, 0) = 0
|
||||
AND contract_template.`CompanyId` = position.`CompanyId`
|
||||
AND contract_template.`DepartmentId` = position.`DepartmentId`;
|
||||
|
||||
DROP PROCEDURE IF EXISTS `ob_scope_add_unique_index_if_clean`;
|
||||
DROP PROCEDURE IF EXISTS `ob_scope_add_index_if_missing`;
|
||||
DROP PROCEDURE IF EXISTS `ob_scope_add_column_if_missing`;
|
||||
|
||||
-- 结果 1:仍未明确部门归属的岗位。必须在岗位管理中补齐。
|
||||
SELECT
|
||||
position.`Id`,
|
||||
position.`PositionCode`,
|
||||
position.`PositionName`,
|
||||
position.`CompanyId`
|
||||
FROM `ob_position` position
|
||||
WHERE position.`DepartmentId` IS NULL
|
||||
AND COALESCE(position.`IsDelete`, 0) = 0;
|
||||
|
||||
-- 结果 2:仍未明确部门归属的入职模板。必须编辑并重新保存。
|
||||
SELECT
|
||||
template.`Id`,
|
||||
template.`TemplateCode`,
|
||||
template.`TemplateName`,
|
||||
template.`CompanyId`
|
||||
FROM `ob_onboarding_template` template
|
||||
WHERE template.`DepartmentId` IS NULL
|
||||
AND COALESCE(template.`IsDelete`, 0) = 0;
|
||||
|
||||
-- 结果 3:仍未明确公司/部门或没有适用岗位的合同模板。必须编辑并重新保存。
|
||||
SELECT
|
||||
contract_template.`Id`,
|
||||
contract_template.`TemplateCode`,
|
||||
contract_template.`TemplateName`,
|
||||
contract_template.`CompanyId`,
|
||||
contract_template.`DepartmentId`,
|
||||
COUNT(position_relation.`Id`) AS `PositionCount`
|
||||
FROM `ob_contract_template` contract_template
|
||||
LEFT JOIN `ob_contract_template_position` position_relation
|
||||
ON position_relation.`ContractTemplateId` = contract_template.`Id`
|
||||
AND COALESCE(position_relation.`IsDelete`, 0) = 0
|
||||
WHERE COALESCE(contract_template.`IsDelete`, 0) = 0
|
||||
GROUP BY
|
||||
contract_template.`Id`,
|
||||
contract_template.`TemplateCode`,
|
||||
contract_template.`TemplateName`,
|
||||
contract_template.`CompanyId`,
|
||||
contract_template.`DepartmentId`
|
||||
HAVING contract_template.`CompanyId` IS NULL
|
||||
OR contract_template.`DepartmentId` IS NULL
|
||||
OR COUNT(position_relation.`Id`) = 0;
|
||||
|
||||
-- 结果 4:检查层级不一致的数据,正常情况下应返回 0 行。
|
||||
SELECT
|
||||
contract_template.`Id` AS `ContractTemplateId`,
|
||||
contract_template.`TemplateName`,
|
||||
position.`Id` AS `PositionId`,
|
||||
position.`PositionName`
|
||||
FROM `ob_contract_template` contract_template
|
||||
INNER JOIN `ob_contract_template_position` relation
|
||||
ON relation.`ContractTemplateId` = contract_template.`Id`
|
||||
INNER JOIN `ob_position` position ON position.`Id` = relation.`PositionId`
|
||||
WHERE contract_template.`CompanyId` <> position.`CompanyId`
|
||||
OR contract_template.`DepartmentId` <> position.`DepartmentId`;
|
||||
|
||||
-- 结果 5:正式员工身份证号或手机号重复时,唯一索引会被安全跳过;请清理后重新运行脚本。
|
||||
SELECT
|
||||
'IdCardNumber' AS `ConflictField`,
|
||||
employee.`IdCardNumber` AS `ConflictValue`,
|
||||
COUNT(*) AS `ConflictCount`
|
||||
FROM `ob_employee` employee
|
||||
WHERE NULLIF(TRIM(employee.`IdCardNumber`), '') IS NOT NULL
|
||||
GROUP BY employee.`IdCardNumber`
|
||||
HAVING COUNT(*) > 1
|
||||
UNION ALL
|
||||
SELECT
|
||||
'Phone' AS `ConflictField`,
|
||||
employee.`Phone` AS `ConflictValue`,
|
||||
COUNT(*) AS `ConflictCount`
|
||||
FROM `ob_employee` employee
|
||||
WHERE NULLIF(TRIM(employee.`Phone`), '') IS NOT NULL
|
||||
GROUP BY employee.`Phone`
|
||||
HAVING COUNT(*) > 1;
|
||||
Reference in New Issue
Block a user