Files
openclaw-config/workspace-sql/skills/table-alias/SKILL.md
T

12 KiB
Raw Blame History

table-alias — 表结构对齐技能

版本: 1.1.1
作者: SQL Agent
创建时间: 2026-08-14
最后更新: 2026-08-14


重要注意事项

⚠️ \n 转义字符处理

问题描述:

MySQL SHOW CREATE TABLE 命令返回的建表语句中,字段定义之间使用字面量 \n 字符(两个字符:反斜杠 + n),而非真正的换行符。这会导致生成的 SQL 脚本格式异常,无法直接执行。

示例:

-- 错误格式(包含字面量 \n
CREATE TABLE `test` (
\n  `id` int NOT NULL,\n  `name` varchar(50),\n  PRIMARY KEY (`id`)
)

解决方案:

在脚本中获取 SHOW CREATE TABLE 输出后,必须经过三步处理:

# 1. cut -f2:提取第二列(SHOW CREATE TABLE 返回 表名+CREATE 语句,制表符分隔)
# 2. sed 's/\\n/\n/g':将字面量 \n 转换为真实换行符
# 3. sed '1d;$d':删除首尾行,提取表体部分
SOURCE_CREATE=$(mysql ... -e "SHOW CREATE TABLE ..." | cut -f2 | sed 's/\\n/\n/g')
TABLE_BODY=$(echo "$SOURCE_CREATE" | sed '1d;$d')

技术细节:

  1. cut -f2 - SHOW CREATE TABLE 返回两列(表名、CREATE 语句),用制表符分隔,必须取第二列

    # 原始输出格式:
    table_name<TAB>CREATE TABLE `table_name` (\n  `id` int...\n)
    
    # 错误:tail -1 仍取整行
    # 正确:cut -f2 只取 CREATE 语句列
    
  2. sed 's/\\n/\n/g' - 将字面量 \n(两个字符)转换为真实换行符(一个字符)

    # 注意转义:sed 中 \\n 匹配字面量 \n,\n 替换为真实换行
    
  3. sed '1d;$d' - 删除第一行(CREATE TABLE ... ()和最后一行() ENGINE=...),提取纯表体

    # 替代失效的正则提取(sed 默认不跨行匹配)
    # 1d = 删除第一行,$d = 删除最后一行
    

已生成脚本的批量修复:

如果脚本已生成但包含字面量 \n,使用以下命令批量修复:

cd /path/to/scripts
for f in *.sql; do sed -i 's/\\n/\n/g' "$f"; done

验证方法:

打开 SQL 文件,检查 CREATE TABLE 语句:

  • 正确:字段定义分布在多行,格式清晰
  • 错误:所有字段定义在一行,包含 \n 字符

功能描述

准生产数据库的表结构同步到VPS 开发库,确保开发环境与准生产环境表结构一致。

同步方向: 准生产(只读)→ VPS(root 可写)

支持场景:

  • 新建表:目标库不存在该表时,执行 CREATE TABLE
  • 修改表:目标库已存在该表时,智能对比并执行 ALTER TABLE
  • 批量同步:支持同步整个数据库的所有表

触发方式

自然语言命令:

同步准生产 dmp_serp 的表结构到 VPS
同步准生产 dmp_smdm 的表结构到 VPS

参数解析:

  • 源数据库:固定为"准生产"
  • 源库名:从命令中提取(如 dmp_serp
  • 目标数据库:固定为"VPS"
  • 目标库名:默认与源库名相同

配置文件

位置: /home/yangxuan/.openclaw/workspace-sql/.db-sync-config.yaml

格式:

# 源数据库配置(准生产 - 只读)
sources:
  - name: 准生产
    host: 100.115.195.188
    port: 50036
    user: witsoftd
    password_env: MYSQL_PWD_WIT
    readonly: true
    description: "准生产环境,只读权限"

# 目标数据库配置(VPS - root)
targets:
  - name: VPS
    host: 101.34.227.188
    port: 3306
    user: root
    password_env: MYSQL_PWD_SQL
    readonly: false
    description: "VPS 开发环境,root 权限"
    # 禁止同步的数据库黑名单
    blacklist:
      - ruoyi-vue-pro
      - mysql
      - sys
      - performance_schema

# 输出配置
output:
  base_dir: /home/yangxuan/codes/xuan-sql/scripts
  date_subdir: true
  write_memory: true

执行流程

1. 解析命令

从自然语言命令中提取:

  • 源库名(如 dmp_serp
  • 目标库名(默认与源库名相同)

2. 读取配置

.db-sync-config.yaml 读取:

  • 源数据库连接信息(准生产)
  • 目标数据库连接信息(VPS
  • 输出路径配置

3. 验证连接

# 验证源库连接(只读)
mysql -h <source_host> -P <source_port> -u <source_user> -p"${PASSWORD}" -e "SELECT 1;"

# 验证目标库连接(root
mysql -h <target_host> -P <target_port> -u <target_user> -p"${PASSWORD}" -e "SELECT 1;"

4. 获取表列表

从源数据库获取所有表:

SHOW TABLES FROM <source_database>;

5. 对比并生成脚本

对每个表执行:

5.1 读取源表结构

SHOW CREATE TABLE <source_database>.<table_name>\G

5.2 读取目标表结构

-- 检查表是否存在
SHOW TABLES FROM <target_database> LIKE '<table_name>';

-- 如果存在,读取结构
SHOW CREATE TABLE <target_database>.<table_name>\G

5.3 智能对比

对比维度:

维度 对比方式 处理策略
表是否存在 SHOW TABLES 不存在 → CREATE TABLE
字段列表 对比 information_schema.COLUMNS 缺失 → ADD COLUMN
字段类型 对比 COLUMN_TYPE 不同 → MODIFY COLUMN
NULL 约束 对比 IS_NULLABLE 不同 → MODIFY COLUMN
默认值 对比 COLUMN_DEFAULT 不同 → MODIFY COLUMN
注释 对比 COLUMN_COMMENT 不同 → MODIFY COLUMN
索引 对比 information_schema.STATISTICS 差异 → DROP/ADD INDEX
主键 对比 COLUMN_KEY 差异 → DROP/ADD PRIMARY KEY

对比算法:

# 伪代码
def compare_tables(source_ddl, target_ddl):
    changes = []
    
    # 1. 目标表不存在 → CREATE
    if target_ddl is None:
        return ['CREATE', source_ddl]
    
    # 2. 解析字段列表
    source_fields = parse_fields(source_ddl)
    target_fields = parse_fields(target_ddl)
    
    # 3. 对比字段
    for field in source_fields:
        if field.name not in target_fields:
            changes.append(['ADD COLUMN', field])
        elif field != target_fields[field.name]:
            changes.append(['MODIFY COLUMN', field])
    
    # 4. 删除多余字段(目标有,源没有)
    for field_name in target_fields:
        if field_name not in source_fields:
            changes.append(['DROP COLUMN', field_name])
    
    # 5. 对比索引(略)
    
    return changes

5.4 生成 SQL 脚本

单表脚本格式:

-- ============================================================
-- 表结构同步脚本:{table_name}
-- 源:准生产 ({source_host}:{source_port})
-- 目标:VPS ({target_host}:{target_port}) {target_database}
-- 生成时间:{timestamp}
-- ============================================================

USE {target_database};

-- 如果表不存在,创建表
CREATE TABLE IF NOT EXISTS {table_name} (
  ...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- 如果表已存在,修改结构
-- 添加缺失字段
ALTER TABLE {table_name} ADD COLUMN {field_name} {type} ...;

-- 修改字段类型
ALTER TABLE {table_name} MODIFY COLUMN {field_name} {type} ...;

-- 删除多余字段
ALTER TABLE {table_name} DROP COLUMN {field_name};

-- 添加索引
ALTER TABLE {table_name} ADD INDEX {index_name} ({columns});

-- ============================================================
-- 验证
-- ============================================================
-- SHOW CREATE TABLE {table_name}\G

6. 执行脚本

对每个生成的脚本:

# 执行单表脚本
mysql -h <target_host> -u <target_user> -p"${PASSWORD}" -D <target_database> < <script_file>

# 捕获错误,继续执行下一个表
if [ $? -ne 0 ]; then
    echo "ERROR: Failed to sync ${table_name}"
    log_error "${table_name}: ${error_message}"
else
    echo "OK: Synced ${table_name}"
    log_success "${table_name}"
fi

7. 记录日志

写入 memory/{date}.md

## 表结构同步 - {timestamp}

**源:** 准生产 `{source_database}`  
**目标:** VPS `{target_database}`  
**处理表数:** {count}  
**成功:** {success_count}  
**失败:** {fail_count}

### 处理的表

| 表名 | 操作 | 状态 | 说明 |
|------|------|------|------|
| table1 | CREATE | ✅ | 新建表 |
| table2 | ALTER | ✅ | 添加 3 个字段 |
| table3 | ALTER | ❌ | 字段类型冲突 |

### 脚本位置

{output_dir}/{date}/ ├── README.md ├── {database}__{table1}struct.sql ├── {database}{table2}__struct.sql └── ...


错误处理

策略: 遇到错误时,记录日志并继续处理下一个表。

常见错误及处理:

错误 原因 处理
ERROR 1138: Invalid use of NULL value 字段有 NULL 值,无法改为 NOT NULL 先更新 NULL 值为默认值,再修改
ERROR 1060: Duplicate column name 字段已存在 跳过,记录警告
ERROR 1054: Unknown column 字段不存在 跳过,记录错误
ERROR 1171: All parts of a PRIMARY KEY must be NOT NULL 主键字段为 NULL 记录错误,需人工处理
连接超时 网络问题 重试 3 次,失败则跳过

安全限制

1. 源数据库限制

  • 固定为"准生产"100.115.195.188:50036
  • 只读权限,无法执行 DDL

2. 目标数据库限制

  • 固定为"VPS"101.34.227.188:3306
  • 黑名单数据库禁止同步:
    • ruoyi-vue-pro
    • mysql
    • sys
    • performance_schema

3. 表数量限制

  • 单次同步表数量 > 50 时,需用户确认

输出产物

1. SQL 脚本文件

路径: /home/yangxuan/codes/xuan-sql/scripts/{YYYYMMDD}/

命名: {database}__{table_name}__struct.sql

2. README.md

# 表结构同步脚本 - {date}

**源:** 准生产 `{source_host}:{source_port}` `{source_database}`  
**目标:** VPS `{target_host}:{target_port}` `{target_database}`  
**生成时间:** {timestamp}  
**执行状态:** ✅ 已完成 / ⚠️ 部分失败

## 脚本清单

| 序号 | 脚本文件 | 操作类型 | 状态 |
|------|---------|---------|------|
| 1 | `{database}__{table1}__struct.sql` | CREATE TABLE | ✅ |
| 2 | `{database}__{table2}__struct.sql` | ALTER TABLE | ✅ |
| ... | ... | ... | ... |

## 执行结果

- 总表数:{total}
- 成功:{success}
- 失败:{fail}

## 验证命令

```sql
SHOW TABLES LIKE '{database_pattern}';
SHOW CREATE TABLE {table_name}\G

### 3. 记忆文件

**路径:** `memory/{date}.md`

**内容:** 执行摘要、表清单、脚本位置

---

## 示例

### 示例 1:同步 dmp_serp

**命令:**

同步准生产 dmp_serp 的表结构到 VPS


**执行:**
1. 读取配置:准生产 → VPS
2. 获取 `dmp_serp` 所有表(如 50 张)
3. 对每个表:
   - 对比结构差异
   - 生成 SQL 脚本
   - 执行脚本
4. 写入 `memory/2026-08-14.md`

**输出:**

/home/yangxuan/codes/xuan-sql/scripts/20260814/ ├── README.md ├── dmp_serp__dmp_om_productinfo__struct.sql ├── dmp_serp__dmp_om_productinfo_cost__struct.sql └── ...


### 示例 2:同步 dmp_smdm

**命令:**

同步准生产 dmp_smdm 的表结构到 VPS


**执行:** 同上,目标库为 `dmp_smdm`

---

## 相关文件

- **技能目录:** `/home/yangxuan/.openclaw/workspace-sql/skills/table-alias/`
- **配置文件:** `/home/yangxuan/.openclaw/workspace-sql/.db-sync-config.yaml`
- **脚本输出:** `/home/yangxuan/codes/xuan-sql/scripts/`
- **记忆文件:** `/home/yangxuan/.openclaw/workspace-sql/memory/`

---

## 版本历史

| 版本 | 日期 | 变更 |
|------|------|------|
| 1.1.2 | 2026-08-14 | 补充 `\n` 转义字符处理的技术细节:`cut -f2` 提取第二列、`sed '1d;$d'` 提取表体 |
| 1.1.1 | 2026-08-14 | 修复 `\n` 转义字符问题:在 `SHOW CREATE TABLE` 输出处理中添加 `sed 's/\\n/\n/g'` 转换 |
| 1.1.0 | 2026-08-14 | 支持单表模式,避免全量同步的耗时和风险 |
| 1.0.0 | 2026-08-14 | 初始版本 |