-- ============================================ -- 统一数据库迁移脚本 -- 将CollisionAvoidanceSystem的空间数据表合并到QAUP-Management数据库 -- 创建时间: 2025-01-15 -- 版本: 1.0.0 -- ============================================ -- ============================================ -- 第一步:启用PostGIS扩展 -- ============================================ -- 启用PostGIS扩展(如果尚未启用) CREATE EXTENSION IF NOT EXISTS postgis; CREATE EXTENSION IF NOT EXISTS postgis_topology; -- 验证PostGIS版本 SELECT PostGIS_Version(); -- ============================================ -- 第二步:创建更新时间戳函数(如果不存在) -- ============================================ CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql; -- ============================================ -- 第三步:创建空间数据核心表 -- ============================================ -- 1. 车辆位置表 (vehicle_locations) - 规范化版本 -- 只存储位置相关数据,车辆基础信息通过关联sys_vehicle_info表获取 CREATE TABLE IF NOT EXISTS vehicle_locations ( id BIGSERIAL PRIMARY KEY, -- 车辆ID(关联sys_vehicle_info.vehicle_id) -- 注意:存储数字ID,不是车牌号 vehicle_id BIGINT NOT NULL, -- PostGIS空间字段 (WGS84坐标系) location GEOMETRY(POINT, 4326) NOT NULL, -- 位置相关属性 altitude DOUBLE PRECISION, heading DOUBLE PRECISION CHECK (heading >= 0 AND heading < 360), speed DOUBLE PRECISION CHECK (speed >= 0), -- 时间戳 timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- 数据质量指标 data_quality VARCHAR(20), -- 审计字段 created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- 车辆位置表索引 CREATE INDEX IF NOT EXISTS idx_vehicle_locations_vehicle_id ON vehicle_locations(vehicle_id); CREATE INDEX IF NOT EXISTS idx_vehicle_locations_timestamp ON vehicle_locations(timestamp DESC); CREATE INDEX IF NOT EXISTS idx_vehicle_locations_location_gist ON vehicle_locations USING GIST(location); CREATE INDEX IF NOT EXISTS idx_vehicle_locations_compound ON vehicle_locations(vehicle_id, timestamp DESC); CREATE INDEX IF NOT EXISTS idx_vehicle_locations_data_quality ON vehicle_locations(data_quality); -- 2. 机场区域表 (airport_areas) CREATE TABLE IF NOT EXISTS airport_areas ( id BIGSERIAL PRIMARY KEY, area_id VARCHAR(50) NOT NULL UNIQUE, name VARCHAR(100) NOT NULL, type VARCHAR(30) NOT NULL, description VARCHAR(500), -- PostGIS空间字段 boundary GEOMETRY(POLYGON, 4326) NOT NULL, -- 速度和限制 speed_limit_kph DOUBLE PRECISION, restricted BOOLEAN DEFAULT false, allowed_vehicle_types JSONB, allowed_aircraft_types JSONB, max_height DOUBLE PRECISION, max_weight DOUBLE PRECISION, -- 时间控制 active_time TIMESTAMP WITH TIME ZONE, expiry_time TIMESTAMP WITH TIME ZONE, -- 区域属性 enabled BOOLEAN NOT NULL DEFAULT true, priority INTEGER NOT NULL DEFAULT 1 CHECK (priority >= 1), -- 版本控制 version BIGINT NOT NULL DEFAULT 1, -- 审计字段 created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- 机场区域表索引 CREATE INDEX IF NOT EXISTS idx_airport_areas_area_id ON airport_areas(area_id); CREATE INDEX IF NOT EXISTS idx_airport_areas_type ON airport_areas(type); CREATE INDEX IF NOT EXISTS idx_airport_areas_enabled ON airport_areas(enabled); CREATE INDEX IF NOT EXISTS idx_airport_areas_boundary_gist ON airport_areas USING GIST(boundary); CREATE INDEX IF NOT EXISTS idx_airport_areas_allowed_vehicles_gin ON airport_areas USING GIN(allowed_vehicle_types); -- 3. 车辆轨迹表 (vehicle_trajectories) CREATE TABLE IF NOT EXISTS vehicle_trajectories ( id BIGSERIAL PRIMARY KEY, vehicle_id BIGINT NOT NULL, trajectory_date DATE NOT NULL, -- PostGIS轨迹线 trajectory_line GEOMETRY(LINESTRING, 4326), -- 统计信息 total_distance DOUBLE PRECISION, max_speed DOUBLE PRECISION, avg_speed DOUBLE PRECISION, duration_seconds INTEGER, point_count INTEGER, -- 时间范围 start_time TIMESTAMP WITH TIME ZONE NOT NULL, end_time TIMESTAMP WITH TIME ZONE NOT NULL, -- 审计字段 created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- 车辆轨迹表索引 CREATE INDEX IF NOT EXISTS idx_vehicle_trajectories_vehicle_id ON vehicle_trajectories(vehicle_id); CREATE INDEX IF NOT EXISTS idx_vehicle_trajectories_date ON vehicle_trajectories(trajectory_date DESC); CREATE INDEX IF NOT EXISTS idx_vehicle_trajectories_line_gist ON vehicle_trajectories USING GIST(trajectory_line); -- ============================================ -- 第四步:创建规则引擎表 -- ============================================ -- 1. 空间规则表 (spatial_rules) CREATE TABLE IF NOT EXISTS spatial_rules ( id BIGSERIAL PRIMARY KEY, rule_id VARCHAR(50) NOT NULL UNIQUE, rule_name VARCHAR(100) NOT NULL, -- 规则类型分类 rule_category VARCHAR(30) NOT NULL CHECK (rule_category IN ( 'ACCESS_CONTROL', 'SPEED_LIMIT', 'VEHICLE_RESTRICTION', 'HEIGHT_LIMIT', 'WEIGHT_LIMIT', 'TIME_RESTRICTION', 'PRIORITY_CONTROL', 'SAFETY_ZONE', 'CUSTOM' )), rule_type VARCHAR(50) NOT NULL, -- 空间对象关联 spatial_object_type VARCHAR(30) NOT NULL CHECK (spatial_object_type IN ( 'AREA', 'ROAD', 'INTERSECTION', 'CUSTOM_GEOMETRY' )), spatial_object_id VARCHAR(50), custom_geometry GEOMETRY(POLYGON, 4326), -- 规则参数 rule_parameters JSONB NOT NULL DEFAULT '{}', applicable_vehicle_types JSONB DEFAULT '[]', applicable_aircraft_types JSONB DEFAULT '[]', -- 告警配置 alert_level VARCHAR(20) NOT NULL DEFAULT 'WARNING' CHECK (alert_level IN ( 'INFO', 'WARNING', 'CRITICAL', 'EMERGENCY' )), alert_message VARCHAR(500), response_actions JSONB DEFAULT '[]', -- 规则状态 status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE' CHECK (status IN ( 'ACTIVE', 'INACTIVE', 'SUSPENDED', 'EXPIRED' )), -- 时间控制 effective_from TIMESTAMP WITH TIME ZONE, effective_until TIMESTAMP WITH TIME ZONE, time_patterns JSONB DEFAULT '[]', -- 优先级 priority INTEGER NOT NULL DEFAULT 1 CHECK (priority >= 1), version BIGINT NOT NULL DEFAULT 1, -- 审计字段 created_by VARCHAR(50), updated_by VARCHAR(50), created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- 空间规则表索引 CREATE INDEX IF NOT EXISTS idx_spatial_rules_rule_id ON spatial_rules(rule_id); CREATE INDEX IF NOT EXISTS idx_spatial_rules_category ON spatial_rules(rule_category); CREATE INDEX IF NOT EXISTS idx_spatial_rules_status ON spatial_rules(status); CREATE INDEX IF NOT EXISTS idx_spatial_rules_custom_geometry_gist ON spatial_rules USING GIST(custom_geometry); CREATE INDEX IF NOT EXISTS idx_spatial_rules_parameters_gin ON spatial_rules USING GIN(rule_parameters); -- 2. 规则违反事件表 (rule_violation_events) CREATE TABLE IF NOT EXISTS rule_violation_events ( id BIGSERIAL PRIMARY KEY, event_id VARCHAR(50) NOT NULL UNIQUE, -- 关联规则 rule_id VARCHAR(50) NOT NULL, -- 违规主体 subject_type VARCHAR(20) NOT NULL CHECK (subject_type IN ('VEHICLE', 'AIRCRAFT')), subject_id VARCHAR(50) NOT NULL, -- 违规详情 violation_type VARCHAR(50) NOT NULL, violation_details JSONB NOT NULL DEFAULT '{}', -- 位置信息 location GEOMETRY(POINT, 4326) NOT NULL, spatial_context VARCHAR(100), -- 违规数据 actual_value JSONB, threshold_value JSONB, -- 严重程度 severity VARCHAR(20) NOT NULL CHECK (severity IN ('LOW', 'MEDIUM', 'HIGH', 'CRITICAL')), -- 响应状态 response_status VARCHAR(20) NOT NULL DEFAULT 'PENDING' CHECK (response_status IN ( 'PENDING', 'ACKNOWLEDGED', 'IN_PROGRESS', 'RESOLVED', 'IGNORED' )), -- 响应动作记录 response_actions_taken JSONB DEFAULT '[]', response_details JSONB DEFAULT '{}', -- 时间信息 detected_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, acknowledged_at TIMESTAMP WITH TIME ZONE, resolved_at TIMESTAMP WITH TIME ZONE, -- 审计字段 created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- 规则违反事件表索引 CREATE INDEX IF NOT EXISTS idx_rule_violations_rule_id ON rule_violation_events(rule_id); CREATE INDEX IF NOT EXISTS idx_rule_violations_subject ON rule_violation_events(subject_type, subject_id); CREATE INDEX IF NOT EXISTS idx_rule_violations_severity ON rule_violation_events(severity); CREATE INDEX IF NOT EXISTS idx_rule_violations_status ON rule_violation_events(response_status); CREATE INDEX IF NOT EXISTS idx_rule_violations_detected_at ON rule_violation_events(detected_at DESC); CREATE INDEX IF NOT EXISTS idx_rule_violations_location_gist ON rule_violation_events USING GIST(location); -- ============================================ -- 第五步:创建业务关联视图 -- ============================================ -- 车辆完整信息视图(基础信息 + 最新位置)- 规范化版本 CREATE OR REPLACE 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 OR REPLACE VIEW vehicle_status_summary AS SELECT COUNT(*) as total_vehicles, COUNT(CASE WHEN last_location_time > NOW() - INTERVAL '5 minutes' THEN 1 END) as active_vehicles, COUNT(CASE WHEN last_location_time > NOW() - INTERVAL '30 minutes' AND last_location_time <= NOW() - INTERVAL '5 minutes' THEN 1 END) as inactive_vehicles, COUNT(CASE WHEN last_location_time IS NULL OR last_location_time <= NOW() - INTERVAL '30 minutes' THEN 1 END) as offline_vehicles, AVG(speed) as avg_speed, MAX(speed) as max_speed FROM vehicle_complete_info; -- ============================================ -- 第六步:创建触发器 -- ============================================ -- 为新表创建自动更新时间戳的触发器 CREATE TRIGGER trigger_vehicle_locations_updated_at BEFORE UPDATE ON vehicle_locations FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER trigger_airport_areas_updated_at BEFORE UPDATE ON airport_areas FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); CREATE TRIGGER trigger_spatial_rules_updated_at BEFORE UPDATE ON spatial_rules FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- ============================================ -- 第七步:添加表注释 -- ============================================ -- 添加表和视图注释 COMMENT ON TABLE vehicle_locations IS '车辆位置信息表(规范化版本)- 只存储位置相关数据,车辆基础信息通过关联sys_vehicle_info表获取'; COMMENT ON COLUMN vehicle_locations.vehicle_id IS '车辆ID,关联sys_vehicle_info.vehicle_id(数字主键)'; COMMENT ON VIEW vehicle_complete_info IS '车辆完整信息视图 - 包含基础信息和最新位置,通过vehicle_id关联'; -- ============================================ -- 第八步:添加外键约束(可选) -- ============================================ -- 外键约束:确保vehicle_id在sys_vehicle_info表中存在 -- 注意:只有在确保数据完整性的情况下才启用 -- ALTER TABLE vehicle_locations -- ADD CONSTRAINT fk_vehicle_locations_vehicle_id -- FOREIGN KEY (vehicle_id) REFERENCES sys_vehicle_info(vehicle_id) -- ON DELETE CASCADE ON UPDATE CASCADE; -- ============================================ -- 第八步:插入示例配置数据 -- ============================================ -- 插入默认机场区域(示例) INSERT INTO airport_areas (area_id, name, type, description, boundary, enabled) VALUES ('RUNWAY_01', '跑道01区域', 'RUNWAY', '主跑道区域', ST_GeomFromText('POLYGON((116.3 39.9, 116.31 39.9, 116.31 39.91, 116.3 39.91, 116.3 39.9))', 4326), true) ON CONFLICT (area_id) DO NOTHING; -- 插入默认安全规则(示例) INSERT INTO spatial_rules (rule_id, rule_name, rule_category, rule_type, spatial_object_type, spatial_object_id, rule_parameters, alert_level, status) VALUES ('SPEED_LIMIT_RUNWAY', '跑道限速规则', 'SPEED_LIMIT', 'MAX_SPEED', 'AREA', 'RUNWAY_01', '{"max_speed_kph": 30}', 'WARNING', 'ACTIVE') ON CONFLICT (rule_id) DO NOTHING; -- ============================================ -- 验证脚本执行结果 -- ============================================ -- 检查PostGIS扩展 SELECT name, default_version, installed_version FROM pg_available_extensions WHERE name IN ('postgis', 'postgis_topology'); -- 检查新创建的表 SELECT schemaname, tablename, tableowner FROM pg_tables WHERE tablename IN ( 'vehicle_locations', 'airport_areas', 'vehicle_trajectories', 'spatial_rules', 'rule_violation_events' ) ORDER BY tablename; -- 检查空间索引 SELECT schemaname, tablename, indexname, indexdef FROM pg_indexes WHERE indexname LIKE '%gist%' AND tablename IN ('vehicle_locations', 'airport_areas', 'vehicle_trajectories', 'spatial_rules', 'rule_violation_events') ORDER BY tablename, indexname; -- 检查视图 SELECT schemaname, viewname, viewowner FROM pg_views WHERE viewname IN ('vehicle_complete_info', 'vehicle_status_summary') ORDER BY viewname; -- ============================================ -- 迁移完成提示 -- ============================================ DO $$ BEGIN RAISE NOTICE '=============================================='; RAISE NOTICE '数据库迁移完成!'; RAISE NOTICE '已成功合并CollisionAvoidanceSystem的空间数据表到QAUP-Management数据库'; RAISE NOTICE '新增表:vehicle_locations, airport_areas, vehicle_trajectories, spatial_rules, rule_violation_events'; RAISE NOTICE '新增视图:vehicle_complete_info, vehicle_status_summary'; RAISE NOTICE '已启用PostGIS扩展支持空间数据操作'; RAISE NOTICE '=============================================='; END $$;