# 数据库迁移脚本指南（PostgreSQL → MySQL）

## 1. 概述

本文档提供了将 urbanLifeline 数据库从 PostgreSQL 迁移到 MySQL（pigx 平台）的完整脚本和指南。

## 2. 数据类型映射

| PostgreSQL | MySQL | 说明 |
|-----------|-------|------|
| VARCHAR(n) | VARCHAR(n) | 字符串 |
| TEXT | TEXT | 长文本 |
| INTEGER | INT | 整数 |
| BIGINT | BIGINT | 长整数 |
| BOOLEAN | TINYINT(1) | 布尔值 |
| TIMESTAMPTZ | DATETIME | 时间戳 |
| JSONB | JSON | JSON数据 |
| NUMERIC(p,s) | DECIMAL(p,s) | 小数 |
| VARCHAR(n)[] | JSON | 数组转JSON |
| SERIAL | INT AUTO_INCREMENT | 自增 |

## 3. pigx-dify 模块数据库脚本

### 3.1 智能体表 (tb_agent)

```sql
-- 智能体配置表
CREATE TABLE `tb_agent` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `agent_id` varchar(50) NOT NULL COMMENT '智能体ID',
  `name` varchar(50) NOT NULL COMMENT '智能体名称',
  `description` varchar(500) DEFAULT NULL COMMENT '智能体描述',
  `link` varchar(500) DEFAULT NULL COMMENT '智能体url',
  `api_key` varchar(500) NOT NULL COMMENT 'dify智能体APIKEY',
  `is_outer` tinyint(1) DEFAULT '0' COMMENT '是否是对外智能体，未登录可用',
  `introduce` varchar(500) NOT NULL COMMENT '引导词',
  `prompt_cards` json DEFAULT NULL COMMENT '提示卡片数组 [{file_id:, prompt:}]',
  `category` varchar(50) NOT NULL COMMENT '分类',
  `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID',
  `creator` varchar(50) DEFAULT NULL COMMENT '创建者',
  `updater` varchar(50) DEFAULT NULL COMMENT '更新者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `delete_time` datetime DEFAULT NULL COMMENT '删除时间',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`agent_id`),
  UNIQUE KEY `uk_optsn` (`optsn`),
  UNIQUE KEY `uk_api_key` (`api_key`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI智能体配置表';
```

### 3.2 对话表 (tb_chat)

```sql
-- AI智能体对话表
CREATE TABLE `tb_chat` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `chat_id` varchar(50) NOT NULL COMMENT '对话ID',
  `agent_id` varchar(50) NOT NULL COMMENT '智能体ID',
  `user_id` varchar(50) NOT NULL COMMENT '用户ID',
  `user_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT '用户类型 1-系统内部人员 0-系统外部人员',
  `title` varchar(500) NOT NULL COMMENT '对话标题',
  `channel` varchar(50) DEFAULT 'agent' COMMENT '对话渠道 agent、wechat',
  `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `delete_time` datetime DEFAULT NULL COMMENT '删除时间',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`chat_id`),
  UNIQUE KEY `uk_optsn` (`optsn`),
  KEY `idx_agent_id` (`agent_id`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI智能体对话表';
```

### 3.3 聊天消息表 (tb_chat_message)

```sql
-- AI智能体对话消息表
CREATE TABLE `tb_chat_message` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `message_id` varchar(50) NOT NULL COMMENT '消息ID',
  `dify_message_id` varchar(100) DEFAULT NULL COMMENT 'Dify消息ID',
  `chat_id` varchar(50) NOT NULL COMMENT '对话ID',
  `role` varchar(50) NOT NULL COMMENT '角色：user-用户/ai-智能体/recipient-来客',
  `content` text NOT NULL COMMENT '消息内容',
  `files` json DEFAULT NULL COMMENT '文件id数组',
  `comment` varchar(50) DEFAULT NULL COMMENT '评价',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `delete_time` datetime DEFAULT NULL COMMENT '删除时间',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`message_id`),
  UNIQUE KEY `uk_optsn` (`optsn`),
  KEY `idx_chat_id` (`chat_id`),
  KEY `idx_dify_message_id` (`dify_message_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI智能体对话消息表';
```

### 3.4 知识库表 (tb_knowledge)

```sql
-- 知识库配置表
CREATE TABLE `tb_knowledge` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `knowledge_id` varchar(50) NOT NULL COMMENT '知识库ID',
  `title` varchar(255) NOT NULL COMMENT '知识库标题',
  `avatar` varchar(255) DEFAULT NULL COMMENT '知识库头像',
  `description` varchar(500) DEFAULT NULL COMMENT '知识库描述',
  `dify_dataset_id` varchar(100) DEFAULT NULL COMMENT 'Dify知识库ID（Dataset ID）',
  `dify_indexing_technique` varchar(50) DEFAULT 'high_quality' COMMENT 'Dify索引方式（high_quality/economy）',
  `embedding_model` varchar(100) DEFAULT NULL COMMENT '向量模型名称',
  `embedding_model_provider` varchar(100) DEFAULT NULL COMMENT '向量模型提供商',
  `rerank_model` varchar(100) DEFAULT NULL COMMENT 'Rerank模型名称',
  `rerank_model_provider` varchar(100) DEFAULT NULL COMMENT 'Rerank模型提供商',
  `reranking_enable` tinyint(1) DEFAULT '0' COMMENT '是否启用Rerank',
  `retrieval_top_k` int DEFAULT '2' COMMENT '检索Top K（返回前K个结果）',
  `retrieval_score_threshold` decimal(3,2) DEFAULT '0.00' COMMENT '检索分数阈值（0.00-1.00）',
  `document_count` int DEFAULT '0' COMMENT '文档数量',
  `total_chunks` int DEFAULT '0' COMMENT '总分段数',
  `service` varchar(50) DEFAULT NULL COMMENT '所属服务 workcase、bidding',
  `project_id` varchar(50) DEFAULT NULL COMMENT 'bidding所属项目ID',
  `category` varchar(50) DEFAULT NULL COMMENT '所属分类',
  `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID',
  `creator` varchar(50) NOT NULL COMMENT '创建者（用户ID）',
  `dept_path` varchar(50) DEFAULT NULL COMMENT '创建者部门路径',
  `updater` varchar(50) DEFAULT NULL COMMENT '更新者',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `delete_time` datetime DEFAULT NULL COMMENT '删除时间',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`optsn`),
  UNIQUE KEY `uk_knowledge_id` (`knowledge_id`),
  UNIQUE KEY `uk_dify_dataset_id` (`dify_dataset_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识库配置表';
```

### 3.5 知识库文件表 (tb_knowledge_file)

```sql
-- 知识库文件表
CREATE TABLE `tb_knowledge_file` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `knowledge_id` varchar(50) NOT NULL COMMENT '知识库ID',
  `file_root_id` varchar(50) NOT NULL COMMENT '文件根ID',
  `file_id` varchar(50) NOT NULL COMMENT '文件ID',
  `dify_file_id` varchar(50) NOT NULL COMMENT 'dify文件ID',
  `version` int NOT NULL DEFAULT '1' COMMENT '文件版本',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `delete_time` datetime DEFAULT NULL COMMENT '删除时间',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`optsn`),
  UNIQUE KEY `uk_knowledge_file` (`knowledge_id`, `file_id`),
  KEY `idx_file_root_id` (`file_root_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='知识库文件表';
```

## 4. pigx-app-server 模块数据库脚本

### 4.1 工单表 (tb_workcase)

```sql
-- 工单表
CREATE TABLE `tb_workcase` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `workcase_id` varchar(50) NOT NULL COMMENT '工单ID',
  `room_id` varchar(50) NOT NULL COMMENT '聊天室ID',
  `user_id` varchar(50) NOT NULL COMMENT '来客ID',
  `username` varchar(200) NOT NULL COMMENT '来客姓名',
  `phone` varchar(20) NOT NULL COMMENT '来客电话',
  `type` varchar(50) NOT NULL COMMENT '故障类型',
  `device` varchar(50) DEFAULT NULL COMMENT '设备名称',
  `device_code` varchar(50) DEFAULT NULL COMMENT '设备代码',
  `device_name_plate` varchar(50) DEFAULT NULL COMMENT '设备名称牌',
  `device_name_plate_img` varchar(50) NOT NULL COMMENT '设备名称牌图片',
  `address` varchar(1000) DEFAULT NULL COMMENT '现场地址',
  `description` varchar(1000) DEFAULT NULL COMMENT '故障描述',
  `imgs` json DEFAULT NULL COMMENT '工单图片id数组',
  `emergency` varchar(50) NOT NULL DEFAULT 'normal' COMMENT '紧急程度 normal-普通 emergency-紧急',
  `status` varchar(50) NOT NULL DEFAULT 'pending' COMMENT '状态 pending-待处理 processing-处理中 done-已完成',
  `processor` varchar(50) DEFAULT NULL COMMENT '处理人',
  `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID',
  `creator` varchar(50) NOT NULL COMMENT '创建人',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `delete_time` datetime DEFAULT NULL COMMENT '删除时间',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`workcase_id`),
  UNIQUE KEY `uk_room_id` (`room_id`),
  UNIQUE KEY `uk_optsn` (`optsn`),
  KEY `idx_user_id` (`user_id`),
  KEY `idx_status` (`status`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工单表';
```

### 4.2 聊天室表 (tb_chat_room)

```sql
-- IM聊天室表
CREATE TABLE `tb_chat_room` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `room_id` varchar(50) NOT NULL COMMENT '聊天室ID',
  `workcase_id` varchar(50) DEFAULT NULL COMMENT '关联工单ID',
  `room_name` varchar(200) NOT NULL COMMENT '聊天室名称',
  `room_type` varchar(20) NOT NULL DEFAULT 'workcase' COMMENT '聊天室类型：workcase-工单客服',
  `status` varchar(20) NOT NULL DEFAULT 'active' COMMENT '状态：active-活跃 closed-已关闭 archived-已归档',
  `guest_id` varchar(50) NOT NULL COMMENT '来客ID（创建者）',
  `guest_name` varchar(100) NOT NULL COMMENT '来客姓名',
  `ai_session_id` varchar(50) DEFAULT NULL COMMENT 'AI对话会话ID（从ai.tb_chat同步）',
  `message_count` int NOT NULL DEFAULT '0' COMMENT '消息总数',
  `device_code` varchar(50) NOT NULL COMMENT '设备代码',
  `last_message_time` datetime DEFAULT NULL COMMENT '最后消息时间',
  `last_message` text DEFAULT NULL COMMENT '最后一条消息内容',
  `comment_level` int DEFAULT '0' COMMENT '服务评分（1-5）',
  `closed_by` varchar(50) DEFAULT NULL COMMENT '关闭人',
  `closed_time` datetime DEFAULT NULL COMMENT '关闭时间',
  `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID',
  `creator` varchar(50) NOT NULL COMMENT '创建人',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `delete_time` datetime DEFAULT NULL COMMENT '删除时间',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`room_id`),
  UNIQUE KEY `uk_workcase_id` (`workcase_id`),
  UNIQUE KEY `uk_optsn` (`optsn`),
  KEY `idx_guest` (`guest_id`, `status`),
  KEY `idx_last_message_time` (`last_message_time`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IM聊天室表，一个工单对应一个聊天室';
```

### 4.3 聊天室成员表 (tb_chat_room_member)

```sql
-- 聊天室成员表
CREATE TABLE `tb_chat_room_member` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `member_id` varchar(50) NOT NULL COMMENT '成员记录ID',
  `room_id` varchar(50) NOT NULL COMMENT '聊天室ID',
  `user_id` varchar(50) NOT NULL COMMENT '用户ID（来客ID或员工ID）',
  `user_type` varchar(20) NOT NULL COMMENT '用户类型：guest-来客 staff-客服 ai-AI助手',
  `user_name` varchar(100) NOT NULL COMMENT '用户名称',
  `status` varchar(20) NOT NULL DEFAULT 'active' COMMENT '状态：active-活跃 left-已离开 removed-被移除',
  `unread_count` int NOT NULL DEFAULT '0' COMMENT '未读消息数',
  `last_read_time` datetime DEFAULT NULL COMMENT '最后阅读时间',
  `last_read_msg_id` varchar(50) DEFAULT NULL COMMENT '最后阅读的消息ID',
  `join_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入时间',
  `leave_time` datetime DEFAULT NULL COMMENT '离开时间',
  `creator` varchar(50) NOT NULL COMMENT '创建人',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`member_id`),
  UNIQUE KEY `uk_room_user` (`room_id`, `user_id`),
  KEY `idx_room_status` (`room_id`, `status`),
  KEY `idx_user` (`user_id`, `user_type`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='聊天室成员表';
```

### 4.4 聊天室消息表 (tb_chat_room_message)

```sql
-- 聊天室消息表
CREATE TABLE `tb_chat_room_message` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `message_id` varchar(50) NOT NULL COMMENT '消息ID',
  `room_id` varchar(50) NOT NULL COMMENT '聊天室ID',
  `sender_id` varchar(50) NOT NULL COMMENT '发送者ID',
  `sender_type` varchar(20) NOT NULL COMMENT '发送者类型：guest-来客 agent-客服 ai-AI助手 system-系统消息',
  `sender_name` varchar(100) NOT NULL COMMENT '发送者名称',
  `message_type` varchar(20) NOT NULL DEFAULT 'text' COMMENT '消息类型',
  `content` text NOT NULL COMMENT '消息内容',
  `files` json DEFAULT NULL COMMENT '附件文件ID数组',
  `content_extra` json DEFAULT NULL COMMENT '扩展内容（会议链接、引用信息等）',
  `reply_to_msg_id` varchar(50) DEFAULT NULL COMMENT '回复的消息ID',
  `is_ai_message` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否AI消息',
  `ai_message_id` varchar(50) DEFAULT NULL COMMENT 'AI原始消息ID',
  `status` varchar(20) NOT NULL DEFAULT 'sent' COMMENT '状态',
  `read_count` int NOT NULL DEFAULT '0' COMMENT '已读人数',
  `send_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发送时间',
  `creator` varchar(50) NOT NULL COMMENT '创建人',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`message_id`),
  KEY `idx_room_time` (`room_id`, `send_time`),
  KEY `idx_sender` (`sender_id`, `sender_type`),
  KEY `idx_ai_message` (`ai_message_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IM聊天消息表';
```

### 4.5 视频会议表 (tb_video_meeting)

```sql
-- Jitsi Meet视频会议表
CREATE TABLE `tb_video_meeting` (
  `optsn` varchar(50) NOT NULL COMMENT '流水号',
  `meeting_id` varchar(50) NOT NULL COMMENT '会议ID（也是Jitsi房间名）',
  `room_id` varchar(50) NOT NULL COMMENT '关联聊天室ID',
  `workcase_id` varchar(50) NOT NULL COMMENT '关联工单ID',
  `meeting_name` varchar(200) NOT NULL COMMENT '会议名称',
  `meeting_password` varchar(50) DEFAULT NULL COMMENT '会议密码',
  `description` varchar(500) DEFAULT NULL COMMENT '会议描述',
  `jwt_token` text DEFAULT NULL COMMENT 'JWT Token（用于身份验证）',
  `jitsi_room_name` varchar(200) NOT NULL COMMENT 'Jitsi房间名',
  `jitsi_server_url` varchar(500) NOT NULL DEFAULT 'https://meet.jit.si' COMMENT 'Jitsi服务器地址',
  `status` varchar(20) NOT NULL DEFAULT 'scheduled' COMMENT '状态',
  `creator_type` varchar(20) NOT NULL COMMENT '创建者类型',
  `creator_name` varchar(100) NOT NULL COMMENT '创建者名称',
  `participant_count` int NOT NULL DEFAULT '0' COMMENT '参与人数',
  `max_participants` int DEFAULT '10' COMMENT '最大参与人数',
  `start_time` datetime NOT NULL COMMENT '定义会议开始时间',
  `end_time` datetime NOT NULL COMMENT '定义会议结束时间',
  `advance` int DEFAULT '5' COMMENT '提前入会时间（分钟）',
  `actual_start_time` datetime DEFAULT NULL COMMENT '真正会议开始时间',
  `actual_end_time` datetime DEFAULT NULL COMMENT '真正会议结束时间',
  `duration_seconds` int DEFAULT '0' COMMENT '会议时长（秒）',
  `iframe_url` text DEFAULT NULL COMMENT 'iframe嵌入URL',
  `config` json DEFAULT NULL COMMENT 'Jitsi配置项',
  `tenant_id` bigint NOT NULL DEFAULT '1' COMMENT '租户ID',
  `creator` varchar(50) NOT NULL COMMENT '创建人',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `delete_time` datetime DEFAULT NULL COMMENT '删除时间',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
  PRIMARY KEY (`meeting_id`),
  UNIQUE KEY `uk_jitsi_room_name` (`jitsi_room_name`),
  KEY `idx_room` (`room_id`, `status`),
  KEY `idx_workcase` (`workcase_id`, `status`),
  KEY `idx_create_time` (`create_time`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Jitsi Meet视频会议表';
```

## 5. 数据迁移步骤

### 5.1 准备工作

```bash
# 1. 导出 PostgreSQL 数据
pg_dump -h localhost -p 5432 -U postgres -d urbanlifeline \
  --data-only \
  --column-inserts \
  --no-owner \
  --no-privileges \
  --no-tablespaces \
  > urbanlifeline_data.sql

# 2. 创建 MySQL 数据库
mysql -u root -p -e "CREATE DATABASE pigx_dify DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
```

### 5.2 执行表结构创建

```bash
# 执行所有建表语句
mysql -u root -p pigx_dify < create_tables.sql
```

### 5.3 数据转换脚本

```python
#!/usr/bin/env python3
# convert_data.py - PostgreSQL 到 MySQL 数据转换脚本

import re
import json

def convert_postgresql_to_mysql(input_file, output_file):
    with open(input_file, 'r', encoding='utf-8') as f:
        content = f.read()

    # 替换 PostgreSQL 特有语法
    replacements = [
        # 布尔值转换
        (r'\btrue\b', '1'),
        (r'\bfalse\b', '0'),
        # 时间戳转换
        (r"now\(\)", "CURRENT_TIMESTAMP"),
        # 数组转JSON
        (r"'{([^}]*)}'::\w+\[\]", lambda m: f"'{json.dumps(m.group(1).split(',') if m.group(1) else [])}'"),
        # Schema 去除
        (r'\b(workcase|ai|sys|message|bidding)\\.', ''),
    ]

    for pattern, replacement in replacements:
        if callable(replacement):
            content = re.sub(pattern, replacement, content)
        else:
            content = re.sub(pattern, replacement, content, flags=re.IGNORECASE)

    # 添加租户ID到每个INSERT语句
    content = add_tenant_id(content)

    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(content)

def add_tenant_id(content):
    """为所有INSERT语句添加tenant_id字段"""
    lines = content.split('\n')
    result = []

    for line in lines:
        if line.startswith('INSERT INTO'):
            # 检查表是否需要tenant_id
            if any(table in line for table in ['tb_agent', 'tb_chat', 'tb_workcase', 'tb_chat_room']):
                # 在VALUES前添加tenant_id字段
                line = re.sub(
                    r'(\([^)]+)\)',
                    r'\1, tenant_id)',
                    line, count=1
                )
                # 在值列表中添加1作为默认租户ID
                line = re.sub(
                    r'VALUES\s*\(([^)]+)\)',
                    r'VALUES (\1, 1)',
                    line
                )
        result.append(line)

    return '\n'.join(result)

if __name__ == '__main__':
    convert_postgresql_to_mysql('urbanlifeline_data.sql', 'pigx_data.sql')
    print("数据转换完成！")
```

### 5.4 导入数据到 MySQL

```bash
# 导入转换后的数据
mysql -u root -p pigx_dify < pigx_data.sql

# 验证数据
mysql -u root -p pigx_dify -e "
SELECT COUNT(*) FROM tb_agent;
SELECT COUNT(*) FROM tb_chat;
SELECT COUNT(*) FROM tb_workcase;
"
```

## 6. 添加租户字段指南

### 6.1 需要添加 tenant_id 的表

所有业务表都需要添加 `tenant_id` 字段：
- tb_agent
- tb_chat
- tb_chat_message（通过chat关联获取）
- tb_knowledge
- tb_workcase
- tb_chat_room
- tb_video_meeting

### 6.2 添加租户字段的SQL模板

```sql
-- 为现有表添加租户字段（如果表已存在）
ALTER TABLE `tb_agent`
ADD COLUMN `tenant_id` BIGINT NOT NULL DEFAULT 1 COMMENT '租户ID' AFTER `category`,
ADD INDEX `idx_tenant_id` (`tenant_id`);

-- 更新现有数据的租户ID（默认为1）
UPDATE tb_agent SET tenant_id = 1 WHERE tenant_id IS NULL;
```

### 6.3 MyBatis-Plus 配置

```java
// 实体类添加租户字段
@TableField(fill = FieldFill.INSERT)
private Long tenantId;

// 自动填充处理器
@Component
public class MybatisPlusMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        PigxUser user = SecurityUtils.getUser();
        this.strictInsertFill(metaObject, "tenantId", Long.class, user.getTenantId());
    }
}

// 租户拦截器配置
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(new TenantLineHandler() {
        @Override
        public Expression getTenantId() {
            return new LongValue(SecurityUtils.getUser().getTenantId());
        }

        @Override
        public String getTenantIdColumn() {
            return "tenant_id";
        }
    }));
    return interceptor;
}
```

## 7. 验证和测试

### 7.1 数据完整性检查

```sql
-- 检查数据迁移完整性
SELECT
    'tb_agent' AS table_name,
    COUNT(*) AS record_count
FROM tb_agent
UNION ALL
SELECT 'tb_chat', COUNT(*) FROM tb_chat
UNION ALL
SELECT 'tb_workcase', COUNT(*) FROM tb_workcase;

-- 检查租户ID设置
SELECT
    tenant_id,
    COUNT(*) AS record_count
FROM tb_agent
GROUP BY tenant_id;
```

### 7.2 索引优化

```sql
-- 添加常用查询索引
ALTER TABLE tb_chat ADD INDEX idx_user_agent (user_id, agent_id);
ALTER TABLE tb_workcase ADD INDEX idx_create_time (create_time DESC);
ALTER TABLE tb_chat_message ADD INDEX idx_chat_time (chat_id, create_time DESC);
```

## 8. 回滚方案

如果迁移失败，可以使用以下方式回滚：

```bash
# 备份当前MySQL数据
mysqldump -u root -p pigx_dify > backup_before_migration.sql

# 如需回滚
mysql -u root -p -e "DROP DATABASE pigx_dify; CREATE DATABASE pigx_dify;"
mysql -u root -p pigx_dify < backup_before_migration.sql
```

## 9. 注意事项

1. **字符集**：确保 MySQL 使用 utf8mb4 字符集
2. **时区**：注意 PostgreSQL 的 TIMESTAMPTZ 转换为 MySQL DATETIME 可能有时区差异
3. **数组类型**：PostgreSQL 的数组类型需要转换为 JSON
4. **事务**：大批量数据导入时注意事务大小
5. **权限**：确保 MySQL 用户有足够权限创建表和索引
6. **外键**：本脚本未创建外键约束，如需要可后续添加

## 10. 迁移清单

- [ ] 导出 PostgreSQL 数据
- [ ] 创建 MySQL 数据库和表结构
- [ ] 执行数据转换脚本
- [ ] 导入数据到 MySQL
- [ ] 添加租户字段和索引
- [ ] 验证数据完整性
- [ ] 测试查询性能
- [ ] 配置 MyBatis-Plus 租户拦截器
- [ ] 执行应用集成测试
- [ ] 准备回滚方案