222 lines
11 KiB
MySQL
222 lines
11 KiB
MySQL
|
|
-- 外部 Excel 岗位全量快照同步。
|
|||
|
|
-- 执行目标:HighGo/PostgreSQL 的 shz schema。
|
|||
|
|
-- 本脚本为增量 migration;不删除现有 job、company、row_work 或监测数据。
|
|||
|
|
|
|||
|
|
BEGIN;
|
|||
|
|
|
|||
|
|
-- 串行化本 migration 的并发执行,避免两个发布进程同时计算 MAX(id)+1。
|
|||
|
|
-- 锁仅持续到本事务提交;重复执行不会改变已存在的业务记录或 Quartz 状态。
|
|||
|
|
SELECT pg_advisory_xact_lock(hashtext('shz.migration_external_job_import'));
|
|||
|
|
|
|||
|
|
ALTER TABLE "shz"."job"
|
|||
|
|
ADD COLUMN IF NOT EXISTS "external_import_flag" CHAR(1) NOT NULL DEFAULT '0',
|
|||
|
|
ADD COLUMN IF NOT EXISTS "external_source_code" VARCHAR(64),
|
|||
|
|
ADD COLUMN IF NOT EXISTS "external_source_name" VARCHAR(200),
|
|||
|
|
ADD COLUMN IF NOT EXISTS "job_fingerprint" VARCHAR(64),
|
|||
|
|
ADD COLUMN IF NOT EXISTS "job_content_fingerprint" VARCHAR(64),
|
|||
|
|
ADD COLUMN IF NOT EXISTS "external_batch_id" VARCHAR(64),
|
|||
|
|
ADD COLUMN IF NOT EXISTS "external_first_seen_at" TIMESTAMP,
|
|||
|
|
ADD COLUMN IF NOT EXISTS "external_last_seen_at" TIMESTAMP;
|
|||
|
|
|
|||
|
|
COMMENT ON COLUMN "shz"."job"."external_import_flag" IS '是否外部 Excel 导入岗位:0否,1是';
|
|||
|
|
COMMENT ON COLUMN "shz"."job"."job_fingerprint" IS '外部岗位身份指纹:FP_V1 + 来源编码 + 标准化岗位链接';
|
|||
|
|
COMMENT ON COLUMN "shz"."job"."job_content_fingerprint" IS '外部岗位内容指纹:用于同一身份岗位的原地更新';
|
|||
|
|
|
|||
|
|
CREATE TABLE IF NOT EXISTS "shz"."job_import_batch" (
|
|||
|
|
"batch_id" VARCHAR(64) PRIMARY KEY,
|
|||
|
|
"file_id" VARCHAR(64) NOT NULL,
|
|||
|
|
"file_name" VARCHAR(500) NOT NULL,
|
|||
|
|
"file_sha256" VARCHAR(64) NOT NULL,
|
|||
|
|
"snapshot_scope" TEXT,
|
|||
|
|
"fingerprint_version" VARCHAR(16) NOT NULL,
|
|||
|
|
"status" VARCHAR(20) NOT NULL,
|
|||
|
|
"total_rows" INTEGER NOT NULL DEFAULT 0,
|
|||
|
|
"valid_rows" INTEGER NOT NULL DEFAULT 0,
|
|||
|
|
"invalid_rows" INTEGER NOT NULL DEFAULT 0,
|
|||
|
|
"duplicate_rows" INTEGER NOT NULL DEFAULT 0,
|
|||
|
|
"insert_count" INTEGER NOT NULL DEFAULT 0,
|
|||
|
|
"update_count" INTEGER NOT NULL DEFAULT 0,
|
|||
|
|
"keep_count" INTEGER NOT NULL DEFAULT 0,
|
|||
|
|
"restore_count" INTEGER NOT NULL DEFAULT 0,
|
|||
|
|
"delete_count" INTEGER NOT NULL DEFAULT 0,
|
|||
|
|
"error_summary" TEXT,
|
|||
|
|
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
"updated_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
"completed_at" TIMESTAMP
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE TABLE IF NOT EXISTS "shz"."job_import_row" (
|
|||
|
|
"row_id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|||
|
|
"batch_id" VARCHAR(64) NOT NULL,
|
|||
|
|
"excel_row_number" INTEGER NOT NULL,
|
|||
|
|
"source_name" VARCHAR(200),
|
|||
|
|
"source_code" VARCHAR(64),
|
|||
|
|
"job_fingerprint" VARCHAR(64),
|
|||
|
|
"content_fingerprint" VARCHAR(64),
|
|||
|
|
"validation_status" VARCHAR(20) NOT NULL,
|
|||
|
|
"result_status" VARCHAR(20) NOT NULL,
|
|||
|
|
"error_message" TEXT,
|
|||
|
|
"raw_payload" TEXT,
|
|||
|
|
"job_id" BIGINT,
|
|||
|
|
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE TABLE IF NOT EXISTS "shz"."job_import_source_alias" (
|
|||
|
|
"alias_name" VARCHAR(200) PRIMARY KEY,
|
|||
|
|
"source_code" VARCHAR(64) NOT NULL,
|
|||
|
|
"website_id" BIGINT,
|
|||
|
|
"is_active" CHAR(1) NOT NULL DEFAULT '1',
|
|||
|
|
"snapshot_required" CHAR(1) NOT NULL DEFAULT '1',
|
|||
|
|
"remark" VARCHAR(500),
|
|||
|
|
"create_time" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|||
|
|
"update_time" TIMESTAMP
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE UNIQUE INDEX IF NOT EXISTS "uk_job_external_active_fingerprint"
|
|||
|
|
ON "shz"."job" ("job_fingerprint")
|
|||
|
|
WHERE "external_import_flag" = '1' AND "del_flag" = '0';
|
|||
|
|
|
|||
|
|
CREATE INDEX IF NOT EXISTS "idx_job_import_batch_sha_status"
|
|||
|
|
ON "shz"."job_import_batch" ("file_sha256", "status");
|
|||
|
|
CREATE INDEX IF NOT EXISTS "idx_job_import_row_batch"
|
|||
|
|
ON "shz"."job_import_row" ("batch_id", "excel_row_number");
|
|||
|
|
CREATE INDEX IF NOT EXISTS "idx_job_external_source_active"
|
|||
|
|
ON "shz"."job" ("external_source_code", "external_import_flag", "del_flag");
|
|||
|
|
|
|||
|
|
-- Quartz 任务默认暂停,防止尚未配置 external-job-import URL/token 时发生无效拉取。
|
|||
|
|
-- 完成环境配置后,在“定时任务”中启用即可;计划为每周三、周六 03:00。
|
|||
|
|
INSERT INTO "shz"."sys_job" (
|
|||
|
|
"job_id", "job_name", "job_group", "invoke_target", "cron_expression",
|
|||
|
|
"misfire_policy", "concurrent", "status", "create_by", "create_time",
|
|||
|
|
"update_by", "update_time", "remark"
|
|||
|
|
)
|
|||
|
|
SELECT
|
|||
|
|
(SELECT COALESCE(MAX("job_id"), 0) + 1 FROM "shz"."sys_job"),
|
|||
|
|
'外部岗位全量同步',
|
|||
|
|
'DEFAULT',
|
|||
|
|
'jobCron.importLatestExternalSnapshot()',
|
|||
|
|
'0 0 3 ? * WED,SAT',
|
|||
|
|
'3',
|
|||
|
|
'1',
|
|||
|
|
'1',
|
|||
|
|
'system',
|
|||
|
|
CURRENT_TIMESTAMP,
|
|||
|
|
'',
|
|||
|
|
NULL,
|
|||
|
|
'外部 Excel 全量快照同步;配置 external-job-import 后由管理员启用'
|
|||
|
|
WHERE NOT EXISTS (
|
|||
|
|
SELECT 1 FROM "shz"."sys_job" WHERE "invoke_target" = 'jobCron.importLatestExternalSnapshot()'
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 为样例及当前采集范围初始化来源管理记录。名称相近的来源不自动合并。
|
|||
|
|
INSERT INTO "shz"."website_management" ("website_name", "website_url", "is_active", "data_type", "del_flag", "create_by", "create_time", "remark")
|
|||
|
|
SELECT seed.website_name, '', '1', '2', '0', 'system', CURRENT_TIMESTAMP, '外部 Excel 岗位采集来源'
|
|||
|
|
FROM (VALUES
|
|||
|
|
('石河子招聘网'), ('智联招聘'), ('天互招聘网'), ('猎聘网'), ('乌鲁木齐快聘网'), ('前程无忧')
|
|||
|
|
) AS seed(website_name)
|
|||
|
|
WHERE NOT EXISTS (
|
|||
|
|
SELECT 1 FROM "shz"."website_management" existing
|
|||
|
|
WHERE existing."website_name" = seed.website_name AND existing."del_flag" = '0'
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
-- 以 alias_name 为幂等键;若此前仅完成了部分迁移,重跑时会补齐网站关联。
|
|||
|
|
INSERT INTO "shz"."job_import_source_alias" AS target ("alias_name", "source_code", "website_id", "is_active", "snapshot_required", "remark")
|
|||
|
|
SELECT seed.alias_name, seed.source_code, website."website_id", '1', '1', '外部 Excel ORG 来源映射'
|
|||
|
|
FROM (VALUES
|
|||
|
|
('石河子招聘网', 'shz_job_net'),
|
|||
|
|
('智联招聘', 'zhaopin'),
|
|||
|
|
('天互招聘网', 'tianhu_job'),
|
|||
|
|
('猎聘网', 'liepin'),
|
|||
|
|
('乌鲁木齐快聘网', 'wlmq_fast_job'),
|
|||
|
|
('前程无忧', '51job')
|
|||
|
|
) AS seed(alias_name, source_code)
|
|||
|
|
LEFT JOIN "shz"."website_management" website ON website."website_name" = seed.alias_name AND website."del_flag" = '0'
|
|||
|
|
ON CONFLICT ("alias_name") DO UPDATE
|
|||
|
|
SET "source_code" = EXCLUDED."source_code",
|
|||
|
|
"website_id" = EXCLUDED."website_id",
|
|||
|
|
"is_active" = EXCLUDED."is_active",
|
|||
|
|
"snapshot_required" = EXCLUDED."snapshot_required",
|
|||
|
|
"remark" = EXCLUDED."remark",
|
|||
|
|
"update_time" = CURRENT_TIMESTAMP
|
|||
|
|
WHERE target."source_code" IS DISTINCT FROM EXCLUDED."source_code"
|
|||
|
|
OR target."website_id" IS DISTINCT FROM EXCLUDED."website_id"
|
|||
|
|
OR target."is_active" IS DISTINCT FROM EXCLUDED."is_active"
|
|||
|
|
OR target."snapshot_required" IS DISTINCT FROM EXCLUDED."snapshot_required"
|
|||
|
|
OR target."remark" IS DISTINCT FROM EXCLUDED."remark";
|
|||
|
|
|
|||
|
|
-- 四字菜单:来源管理、入库监测、采集趋势、统计分析。
|
|||
|
|
INSERT INTO "shz"."sys_menu" (
|
|||
|
|
"menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
|
|||
|
|
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "remark"
|
|||
|
|
)
|
|||
|
|
SELECT (SELECT COALESCE(MAX("menu_id"), 0) + 1 FROM "shz"."sys_menu"),
|
|||
|
|
'招聘信息采集监测分析', 0, 99, 'recruit-monitor', '', '', 'RecruitMonitor',
|
|||
|
|
1, 0, 'M', '0', '0', 'cms:recruit:root', 'chart', 'system', CURRENT_TIMESTAMP, '外部岗位采集监测分析根菜单'
|
|||
|
|
WHERE NOT EXISTS (SELECT 1 FROM "shz"."sys_menu" WHERE "perms" = 'cms:recruit:root');
|
|||
|
|
|
|||
|
|
INSERT INTO "shz"."sys_menu" (
|
|||
|
|
"menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
|
|||
|
|
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "remark"
|
|||
|
|
)
|
|||
|
|
SELECT ids."base_id" + ROW_NUMBER() OVER (ORDER BY seed.order_num),
|
|||
|
|
seed.menu_name, parent."menu_id", seed.order_num, seed.path, seed.component, '', seed.route_name,
|
|||
|
|
1, 0, 'C', '0', '0', seed.perms, 'table', 'system', CURRENT_TIMESTAMP, seed.remark
|
|||
|
|
FROM (VALUES
|
|||
|
|
('来源管理', 1, 'recruit/source', 'Recruit/Source/index', 'RecruitSource', 'cms:recruit:source:list', '外部岗位来源与别名管理'),
|
|||
|
|
('入库监测', 2, 'recruit/monitor', 'Recruit/Monitor/index', 'RecruitMonitor', 'cms:recruit:monitor:list', '外部岗位导入批次监测'),
|
|||
|
|
('采集趋势', 3, 'recruit/trend', 'Recruit/Trend/index', 'RecruitTrend', 'cms:recruit:trend:list', '外部岗位采集趋势'),
|
|||
|
|
('统计分析', 4, 'recruit/analysis', 'Recruit/Analysis/index', 'RecruitAnalysis', 'cms:recruit:analysis:list', '外部岗位统计分析')
|
|||
|
|
) AS seed(menu_name, order_num, path, component, route_name, perms, remark)
|
|||
|
|
JOIN "shz"."sys_menu" parent ON parent."perms" = 'cms:recruit:root'
|
|||
|
|
CROSS JOIN (SELECT COALESCE(MAX("menu_id"), 0) AS "base_id" FROM "shz"."sys_menu") ids
|
|||
|
|
WHERE NOT EXISTS (SELECT 1 FROM "shz"."sys_menu" existing WHERE existing."perms" = seed.perms);
|
|||
|
|
|
|||
|
|
INSERT INTO "shz"."sys_menu" (
|
|||
|
|
"menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
|
|||
|
|
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "remark"
|
|||
|
|
)
|
|||
|
|
SELECT (SELECT COALESCE(MAX("menu_id"), 0) + 1 FROM "shz"."sys_menu"),
|
|||
|
|
'手动导入', parent."menu_id", 1, '', '', '', '', 1, 0, 'F', '0', '0',
|
|||
|
|
'cms:recruit:import:manual', '#', 'system', CURRENT_TIMESTAMP, '手动拉取并导入最新外部 Excel'
|
|||
|
|
FROM "shz"."sys_menu" parent
|
|||
|
|
WHERE parent."perms" = 'cms:recruit:monitor:list'
|
|||
|
|
AND NOT EXISTS (SELECT 1 FROM "shz"."sys_menu" WHERE "perms" = 'cms:recruit:import:manual');
|
|||
|
|
|
|||
|
|
INSERT INTO "shz"."sys_menu" (
|
|||
|
|
"menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
|
|||
|
|
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "remark"
|
|||
|
|
)
|
|||
|
|
SELECT (SELECT COALESCE(MAX("menu_id"), 0) + 1 FROM "shz"."sys_menu"),
|
|||
|
|
'来源维护', parent."menu_id", 1, '', '', '', '', 1, 0, 'F', '0', '0',
|
|||
|
|
'cms:recruit:source:edit', '#', 'system', CURRENT_TIMESTAMP, '维护外部来源和来源别名'
|
|||
|
|
FROM "shz"."sys_menu" parent
|
|||
|
|
WHERE parent."perms" = 'cms:recruit:source:list'
|
|||
|
|
AND NOT EXISTS (SELECT 1 FROM "shz"."sys_menu" WHERE "perms" = 'cms:recruit:source:edit');
|
|||
|
|
|
|||
|
|
INSERT INTO "shz"."sys_menu" (
|
|||
|
|
"menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "route_name",
|
|||
|
|
"is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "remark"
|
|||
|
|
)
|
|||
|
|
SELECT (SELECT COALESCE(MAX("menu_id"), 0) + 1 FROM "shz"."sys_menu"),
|
|||
|
|
'监测维护', parent."menu_id", 2, '', '', '', '', 1, 0, 'F', '0', '0',
|
|||
|
|
'cms:recruit:monitor:edit', '#', 'system', CURRENT_TIMESTAMP, '维护导入监测记录'
|
|||
|
|
FROM "shz"."sys_menu" parent
|
|||
|
|
WHERE parent."perms" = 'cms:recruit:monitor:list'
|
|||
|
|
AND NOT EXISTS (SELECT 1 FROM "shz"."sys_menu" WHERE "perms" = 'cms:recruit:monitor:edit');
|
|||
|
|
|
|||
|
|
INSERT INTO "shz"."sys_role_menu" ("role_id", "menu_id")
|
|||
|
|
SELECT role."role_id", menu."menu_id"
|
|||
|
|
FROM "shz"."sys_role" role
|
|||
|
|
JOIN "shz"."sys_menu" menu ON menu."perms" IN (
|
|||
|
|
'cms:recruit:root', 'cms:recruit:source:list', 'cms:recruit:monitor:list',
|
|||
|
|
'cms:recruit:trend:list', 'cms:recruit:analysis:list', 'cms:recruit:import:manual',
|
|||
|
|
'cms:recruit:source:edit', 'cms:recruit:monitor:edit'
|
|||
|
|
)
|
|||
|
|
WHERE role."role_key" = 'admin'
|
|||
|
|
AND NOT EXISTS (
|
|||
|
|
SELECT 1 FROM "shz"."sys_role_menu" existing
|
|||
|
|
WHERE existing."role_id" = role."role_id" AND existing."menu_id" = menu."menu_id"
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
COMMIT;
|