441 lines
15 KiB
PL/PgSQL
441 lines
15 KiB
PL/PgSQL
-- ============================================
|
||
-- 数据模型统一重构脚本
|
||
-- 目标:统一vehicle_id为数字ID,license_plate为车牌号
|
||
-- 创建时间:2025-01-15
|
||
-- 执行模式:方案B - 完全统一数据模型
|
||
-- ============================================
|
||
|
||
-- 开始事务
|
||
BEGIN;
|
||
|
||
-- 设置错误处理
|
||
\set ON_ERROR_STOP on
|
||
|
||
-- ============================================
|
||
-- 第一阶段:数据结构准备
|
||
-- ============================================
|
||
|
||
-- 创建车辆ID映射表(临时)
|
||
CREATE TABLE IF NOT EXISTS vehicle_id_mapping (
|
||
license_plate VARCHAR(50) PRIMARY KEY,
|
||
old_vehicle_id VARCHAR(50),
|
||
new_vehicle_id BIGINT
|
||
);
|
||
|
||
-- 填充映射表数据
|
||
INSERT INTO vehicle_id_mapping (license_plate, old_vehicle_id, new_vehicle_id)
|
||
SELECT
|
||
license_plate_number as license_plate,
|
||
NULL as old_vehicle_id,
|
||
vehicle_id as new_vehicle_id
|
||
FROM sys_vehicle_info
|
||
ON CONFLICT (license_plate) DO NOTHING;
|
||
|
||
-- 从CollisionAvoidanceSystem表中获取现有车牌号
|
||
INSERT INTO vehicle_id_mapping (license_plate, old_vehicle_id, new_vehicle_id)
|
||
SELECT DISTINCT
|
||
vehicle_id as license_plate,
|
||
vehicle_id as old_vehicle_id,
|
||
NULL::BIGINT as new_vehicle_id
|
||
FROM vehicle_locations
|
||
WHERE vehicle_id NOT IN (SELECT license_plate FROM vehicle_id_mapping)
|
||
ON CONFLICT (license_plate) DO NOTHING;
|
||
|
||
-- 为新车牌号分配数字ID
|
||
DO $$
|
||
DECLARE
|
||
max_id BIGINT;
|
||
rec RECORD;
|
||
BEGIN
|
||
-- 获取当前最大车辆ID
|
||
SELECT COALESCE(MAX(vehicle_id), 0) INTO max_id FROM sys_vehicle_info;
|
||
|
||
-- 为没有数字ID的车牌号分配新ID
|
||
FOR rec IN
|
||
SELECT license_plate FROM vehicle_id_mapping
|
||
WHERE new_vehicle_id IS NULL
|
||
ORDER BY license_plate
|
||
LOOP
|
||
max_id := max_id + 1;
|
||
UPDATE vehicle_id_mapping
|
||
SET new_vehicle_id = max_id
|
||
WHERE license_plate = rec.license_plate;
|
||
END LOOP;
|
||
END $$;
|
||
|
||
-- ============================================
|
||
-- 第二阶段:QAUP-Management表结构变更
|
||
-- ============================================
|
||
|
||
-- 1. 重命名sys_vehicle_info表中的字段
|
||
ALTER TABLE sys_vehicle_info RENAME COLUMN license_plate_number TO license_plate;
|
||
|
||
-- 2. 为新车牌号添加车辆记录
|
||
INSERT INTO sys_vehicle_info (
|
||
vehicle_id, license_plate, vin_number, type_id, brand,
|
||
owning_unit, contact_person, phone_number, image_url,
|
||
create_by, create_time, update_by, update_time, remark
|
||
)
|
||
SELECT
|
||
vim.new_vehicle_id,
|
||
vim.license_plate,
|
||
'AUTO_' || vim.license_plate as vin_number,
|
||
1 as type_id, -- 默认类型,需要根据实际情况调整
|
||
'未知' as brand,
|
||
'自动导入' as owning_unit,
|
||
'系统' as contact_person,
|
||
'' as phone_number,
|
||
'' as image_url,
|
||
'system' as create_by,
|
||
NOW() as create_time,
|
||
'system' as update_by,
|
||
NOW() as update_time,
|
||
'数据模型统一时自动创建' as remark
|
||
FROM vehicle_id_mapping vim
|
||
WHERE vim.new_vehicle_id NOT IN (SELECT vehicle_id FROM sys_vehicle_info)
|
||
AND vim.old_vehicle_id IS NOT NULL;
|
||
|
||
-- ============================================
|
||
-- 第三阶段:CollisionAvoidanceSystem表结构变更
|
||
-- ============================================
|
||
|
||
-- 1. 处理vehicle_locations表
|
||
-- 添加新字段
|
||
ALTER TABLE vehicle_locations ADD COLUMN IF NOT EXISTS license_plate VARCHAR(50);
|
||
ALTER TABLE vehicle_locations ADD COLUMN IF NOT EXISTS vehicle_id_new BIGINT;
|
||
|
||
-- 填充新字段数据
|
||
UPDATE vehicle_locations vl
|
||
SET
|
||
license_plate = vl.vehicle_id,
|
||
vehicle_id_new = vim.new_vehicle_id
|
||
FROM vehicle_id_mapping vim
|
||
WHERE vl.vehicle_id = vim.license_plate;
|
||
|
||
-- 2. 处理vehicle_trajectories表
|
||
-- 添加新字段
|
||
ALTER TABLE vehicle_trajectories ADD COLUMN IF NOT EXISTS license_plate VARCHAR(50);
|
||
ALTER TABLE vehicle_trajectories ADD COLUMN IF NOT EXISTS vehicle_id_new BIGINT;
|
||
|
||
-- 填充新字段数据
|
||
UPDATE vehicle_trajectories vt
|
||
SET
|
||
license_plate = vt.vehicle_id,
|
||
vehicle_id_new = vim.new_vehicle_id
|
||
FROM vehicle_id_mapping vim
|
||
WHERE vt.vehicle_id = vim.license_plate;
|
||
|
||
-- 3. 处理vehicle_commands表
|
||
-- 添加新字段
|
||
ALTER TABLE vehicle_commands ADD COLUMN IF NOT EXISTS license_plate VARCHAR(50);
|
||
ALTER TABLE vehicle_commands ADD COLUMN IF NOT EXISTS vehicle_id_new BIGINT;
|
||
|
||
-- 填充新字段数据
|
||
UPDATE vehicle_commands vc
|
||
SET
|
||
license_plate = vc.vehicle_id,
|
||
vehicle_id_new = vim.new_vehicle_id
|
||
FROM vehicle_id_mapping vim
|
||
WHERE vc.vehicle_id = vim.license_plate;
|
||
|
||
-- 4. 处理rule_violation_events表
|
||
-- 添加新字段
|
||
ALTER TABLE rule_violation_events ADD COLUMN IF NOT EXISTS license_plate VARCHAR(50);
|
||
ALTER TABLE rule_violation_events ADD COLUMN IF NOT EXISTS vehicle_id_new BIGINT;
|
||
|
||
-- 填充新字段数据(只处理车辆类型的事件)
|
||
UPDATE rule_violation_events rve
|
||
SET
|
||
license_plate = rve.subject_id,
|
||
vehicle_id_new = vim.new_vehicle_id
|
||
FROM vehicle_id_mapping vim
|
||
WHERE rve.subject_id = vim.license_plate
|
||
AND rve.subject_type = 'VEHICLE';
|
||
|
||
-- ============================================
|
||
-- 第四阶段:数据完整性验证
|
||
-- ============================================
|
||
|
||
-- 验证数据完整性
|
||
DO $$
|
||
DECLARE
|
||
missing_data_count INTEGER;
|
||
total_records INTEGER;
|
||
BEGIN
|
||
-- 检查vehicle_locations表
|
||
SELECT COUNT(*) INTO missing_data_count
|
||
FROM vehicle_locations
|
||
WHERE license_plate IS NULL OR vehicle_id_new IS NULL;
|
||
|
||
SELECT COUNT(*) INTO total_records FROM vehicle_locations;
|
||
|
||
IF missing_data_count > 0 THEN
|
||
RAISE EXCEPTION 'vehicle_locations表数据迁移不完整: %/%', missing_data_count, total_records;
|
||
END IF;
|
||
|
||
-- 检查vehicle_trajectories表
|
||
SELECT COUNT(*) INTO missing_data_count
|
||
FROM vehicle_trajectories
|
||
WHERE license_plate IS NULL OR vehicle_id_new IS NULL;
|
||
|
||
SELECT COUNT(*) INTO total_records FROM vehicle_trajectories;
|
||
|
||
IF missing_data_count > 0 THEN
|
||
RAISE EXCEPTION 'vehicle_trajectories表数据迁移不完整: %/%', missing_data_count, total_records;
|
||
END IF;
|
||
|
||
-- 检查vehicle_commands表
|
||
SELECT COUNT(*) INTO missing_data_count
|
||
FROM vehicle_commands
|
||
WHERE license_plate IS NULL OR vehicle_id_new IS NULL;
|
||
|
||
SELECT COUNT(*) INTO total_records FROM vehicle_commands;
|
||
|
||
IF missing_data_count > 0 THEN
|
||
RAISE EXCEPTION 'vehicle_commands表数据迁移不完整: %/%', missing_data_count, total_records;
|
||
END IF;
|
||
|
||
RAISE NOTICE '数据完整性验证通过!';
|
||
END $$;
|
||
|
||
-- ============================================
|
||
-- 第五阶段:结构清理和字段重命名
|
||
-- ============================================
|
||
|
||
-- 1. 删除旧字段,重命名新字段 - vehicle_locations
|
||
ALTER TABLE vehicle_locations DROP COLUMN vehicle_id;
|
||
ALTER TABLE vehicle_locations RENAME COLUMN vehicle_id_new TO vehicle_id;
|
||
|
||
-- 2. 删除旧字段,重命名新字段 - vehicle_trajectories
|
||
ALTER TABLE vehicle_trajectories DROP COLUMN vehicle_id;
|
||
ALTER TABLE vehicle_trajectories RENAME COLUMN vehicle_id_new TO vehicle_id;
|
||
|
||
-- 3. 删除旧字段,重命名新字段 - vehicle_commands
|
||
ALTER TABLE vehicle_commands DROP COLUMN vehicle_id;
|
||
ALTER TABLE vehicle_commands RENAME COLUMN vehicle_id_new TO vehicle_id;
|
||
|
||
-- 4. 删除旧字段,重命名新字段 - rule_violation_events
|
||
-- 注意:这里需要谨慎处理,因为subject_id可能不只是车辆ID
|
||
ALTER TABLE rule_violation_events ADD COLUMN IF NOT EXISTS subject_id_new VARCHAR(50);
|
||
UPDATE rule_violation_events SET subject_id_new =
|
||
CASE
|
||
WHEN subject_type = 'VEHICLE' THEN vehicle_id_new::VARCHAR
|
||
ELSE subject_id
|
||
END;
|
||
ALTER TABLE rule_violation_events DROP COLUMN subject_id;
|
||
ALTER TABLE rule_violation_events RENAME COLUMN subject_id_new TO subject_id;
|
||
|
||
-- ============================================
|
||
-- 第六阶段:重建索引和约束
|
||
-- ============================================
|
||
|
||
-- 1. vehicle_locations表索引
|
||
DROP INDEX IF EXISTS idx_vehicle_locations_vehicle_id;
|
||
DROP INDEX IF EXISTS idx_vehicle_locations_license_plate;
|
||
CREATE INDEX idx_vehicle_locations_vehicle_id ON vehicle_locations(vehicle_id);
|
||
CREATE INDEX idx_vehicle_locations_license_plate ON vehicle_locations(license_plate);
|
||
|
||
-- 2. vehicle_trajectories表索引
|
||
DROP INDEX IF EXISTS idx_vehicle_trajectories_vehicle_id;
|
||
DROP INDEX IF EXISTS idx_vehicle_trajectories_license_plate;
|
||
CREATE INDEX idx_vehicle_trajectories_vehicle_id ON vehicle_trajectories(vehicle_id);
|
||
CREATE INDEX idx_vehicle_trajectories_license_plate ON vehicle_trajectories(license_plate);
|
||
|
||
-- 3. vehicle_commands表索引
|
||
DROP INDEX IF EXISTS idx_vehicle_commands_vehicle_id;
|
||
DROP INDEX IF EXISTS idx_vehicle_commands_license_plate;
|
||
CREATE INDEX idx_vehicle_commands_vehicle_id ON vehicle_commands(vehicle_id);
|
||
CREATE INDEX idx_vehicle_commands_license_plate ON vehicle_commands(license_plate);
|
||
|
||
-- 4. rule_violation_events表索引
|
||
DROP INDEX IF EXISTS idx_rule_violations_license_plate;
|
||
CREATE INDEX idx_rule_violations_license_plate ON rule_violation_events(license_plate) WHERE subject_type = 'VEHICLE';
|
||
|
||
-- ============================================
|
||
-- 第七阶段:添加外键约束
|
||
-- ============================================
|
||
|
||
-- 添加外键约束(可选,根据需要启用)
|
||
-- ALTER TABLE vehicle_locations ADD CONSTRAINT fk_vehicle_locations_vehicle_id
|
||
-- FOREIGN KEY (vehicle_id) REFERENCES sys_vehicle_info(vehicle_id);
|
||
|
||
-- ALTER TABLE vehicle_trajectories ADD CONSTRAINT fk_vehicle_trajectories_vehicle_id
|
||
-- FOREIGN KEY (vehicle_id) REFERENCES sys_vehicle_info(vehicle_id);
|
||
|
||
-- ALTER TABLE vehicle_commands ADD CONSTRAINT fk_vehicle_commands_vehicle_id
|
||
-- FOREIGN KEY (vehicle_id) REFERENCES sys_vehicle_info(vehicle_id);
|
||
|
||
-- ============================================
|
||
-- 第八阶段:更新业务视图
|
||
-- ============================================
|
||
|
||
-- 删除旧视图
|
||
DROP VIEW IF EXISTS vehicle_complete_info;
|
||
DROP VIEW IF EXISTS vehicle_status_summary;
|
||
DROP VIEW IF EXISTS vehicle_info_with_location;
|
||
DROP VIEW IF EXISTS vehicle_trajectory_view;
|
||
|
||
-- 重新创建统一的业务视图
|
||
CREATE VIEW vehicle_complete_info AS
|
||
SELECT
|
||
vi.vehicle_id,
|
||
vi.license_plate,
|
||
vi.vin_number,
|
||
vi.type_id,
|
||
vt.type_name,
|
||
vi.brand,
|
||
vi.owning_unit,
|
||
vi.contact_person,
|
||
vi.phone_number,
|
||
vi.image_url,
|
||
vl.location,
|
||
vl.altitude,
|
||
vl.heading,
|
||
vl.speed,
|
||
vl.timestamp as last_location_time,
|
||
vl.data_quality,
|
||
vi.create_time,
|
||
vi.update_time
|
||
FROM sys_vehicle_info vi
|
||
LEFT JOIN sys_vehicle_type vt ON vi.type_id = vt.type_id
|
||
LEFT JOIN LATERAL (
|
||
SELECT * FROM vehicle_locations
|
||
WHERE vehicle_id = vi.vehicle_id
|
||
ORDER BY timestamp DESC
|
||
LIMIT 1
|
||
) vl ON true;
|
||
|
||
-- 车辆状态统计视图
|
||
CREATE VIEW vehicle_status_summary AS
|
||
SELECT
|
||
vehicle_type,
|
||
COUNT(*) as total_vehicles,
|
||
COUNT(CASE WHEN timestamp > NOW() - INTERVAL '5 minutes' THEN 1 END) as active_vehicles,
|
||
COUNT(CASE WHEN timestamp <= NOW() - INTERVAL '5 minutes' THEN 1 END) as inactive_vehicles,
|
||
AVG(speed) as avg_speed,
|
||
MAX(speed) as max_speed
|
||
FROM vehicle_locations vl
|
||
WHERE timestamp > NOW() - INTERVAL '24 hours'
|
||
GROUP BY vehicle_type;
|
||
|
||
-- 车辆信息与位置关联视图
|
||
CREATE VIEW vehicle_info_with_location AS
|
||
SELECT
|
||
vi.vehicle_id,
|
||
vi.license_plate,
|
||
vi.brand,
|
||
vi.owning_unit,
|
||
vt.type_name as vehicle_type_name,
|
||
vl.vehicle_type as location_vehicle_type,
|
||
vl.location,
|
||
ST_X(vl.location) as longitude,
|
||
ST_Y(vl.location) as latitude,
|
||
vl.altitude,
|
||
vl.heading,
|
||
vl.speed,
|
||
vl.timestamp as last_update_time,
|
||
CASE
|
||
WHEN vl.timestamp > NOW() - INTERVAL '5 minutes' THEN 'ACTIVE'
|
||
WHEN vl.timestamp > NOW() - INTERVAL '30 minutes' THEN 'INACTIVE'
|
||
ELSE 'OFFLINE'
|
||
END as status
|
||
FROM sys_vehicle_info vi
|
||
LEFT JOIN sys_vehicle_type vt ON vi.type_id = vt.type_id
|
||
LEFT JOIN LATERAL (
|
||
SELECT * FROM vehicle_locations
|
||
WHERE vehicle_id = vi.vehicle_id
|
||
ORDER BY timestamp DESC
|
||
LIMIT 1
|
||
) vl ON true;
|
||
|
||
-- 车辆轨迹查询视图
|
||
CREATE VIEW vehicle_trajectory_view AS
|
||
SELECT
|
||
vi.vehicle_id,
|
||
vi.license_plate,
|
||
vi.brand,
|
||
vt.trajectory_date,
|
||
vt.trajectory_line,
|
||
vt.total_distance,
|
||
vt.max_speed,
|
||
vt.avg_speed,
|
||
vt.duration_seconds,
|
||
vt.start_time,
|
||
vt.end_time
|
||
FROM sys_vehicle_info vi
|
||
INNER JOIN vehicle_trajectories vt ON vt.vehicle_id = vi.vehicle_id
|
||
LEFT JOIN sys_vehicle_type vtype ON vi.type_id = vtype.type_id;
|
||
|
||
-- ============================================
|
||
-- 第九阶段:添加字段注释
|
||
-- ============================================
|
||
|
||
-- sys_vehicle_info表字段注释
|
||
COMMENT ON COLUMN sys_vehicle_info.license_plate IS '车牌号(统一字段名)';
|
||
|
||
-- vehicle_locations表字段注释
|
||
COMMENT ON COLUMN vehicle_locations.vehicle_id IS '车辆ID(数字主键,关联sys_vehicle_info.vehicle_id)';
|
||
COMMENT ON COLUMN vehicle_locations.license_plate IS '车牌号(业务标识符)';
|
||
|
||
-- vehicle_trajectories表字段注释
|
||
COMMENT ON COLUMN vehicle_trajectories.vehicle_id IS '车辆ID(数字主键,关联sys_vehicle_info.vehicle_id)';
|
||
COMMENT ON COLUMN vehicle_trajectories.license_plate IS '车牌号(业务标识符)';
|
||
|
||
-- vehicle_commands表字段注释
|
||
COMMENT ON COLUMN vehicle_commands.vehicle_id IS '车辆ID(数字主键,关联sys_vehicle_info.vehicle_id)';
|
||
COMMENT ON COLUMN vehicle_commands.license_plate IS '车牌号(业务标识符)';
|
||
|
||
-- rule_violation_events表字段注释
|
||
COMMENT ON COLUMN rule_violation_events.license_plate IS '车牌号(仅当subject_type为VEHICLE时有效)';
|
||
|
||
-- ============================================
|
||
-- 第十阶段:清理临时数据
|
||
-- ============================================
|
||
|
||
-- 删除临时映射表
|
||
DROP TABLE IF EXISTS vehicle_id_mapping;
|
||
|
||
-- ============================================
|
||
-- 最终验证
|
||
-- ============================================
|
||
|
||
DO $$
|
||
DECLARE
|
||
qaup_count INTEGER;
|
||
locations_count INTEGER;
|
||
trajectories_count INTEGER;
|
||
commands_count INTEGER;
|
||
violations_count INTEGER;
|
||
BEGIN
|
||
-- 统计各表记录数
|
||
SELECT COUNT(*) INTO qaup_count FROM sys_vehicle_info;
|
||
SELECT COUNT(*) INTO locations_count FROM vehicle_locations;
|
||
SELECT COUNT(*) INTO trajectories_count FROM vehicle_trajectories;
|
||
SELECT COUNT(*) INTO commands_count FROM vehicle_commands;
|
||
SELECT COUNT(*) INTO violations_count FROM rule_violation_events WHERE subject_type = 'VEHICLE';
|
||
|
||
-- 输出统计信息
|
||
RAISE NOTICE '==============================================';
|
||
RAISE NOTICE '数据模型统一重构完成!';
|
||
RAISE NOTICE '==============================================';
|
||
RAISE NOTICE '车辆信息记录: %', qaup_count;
|
||
RAISE NOTICE '位置记录: %', locations_count;
|
||
RAISE NOTICE '轨迹记录: %', trajectories_count;
|
||
RAISE NOTICE '指令记录: %', commands_count;
|
||
RAISE NOTICE '违规事件记录: %', violations_count;
|
||
RAISE NOTICE '==============================================';
|
||
RAISE NOTICE '主要改进:';
|
||
RAISE NOTICE '1. 统一vehicle_id为数字主键';
|
||
RAISE NOTICE '2. 统一license_plate为车牌号字段名';
|
||
RAISE NOTICE '3. 消除所有字段名不一致';
|
||
RAISE NOTICE '4. 重建了所有业务视图';
|
||
RAISE NOTICE '5. 优化了索引结构';
|
||
RAISE NOTICE '==============================================';
|
||
END $$;
|
||
|
||
-- 提交事务
|
||
COMMIT;
|
||
|
||
-- 显示完成消息
|
||
\echo '数据模型统一重构脚本执行完成!'
|
||
\echo '请验证数据完整性和功能正常性。' |