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

483 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# table-alias — 表结构对齐技能
**版本:** 1.1.1
**作者:** SQL Agent
**创建时间:** 2026-08-14
**最后更新:** 2026-08-14
---
## 重要注意事项
### ⚠️ `\n` 转义字符处理
**问题描述:**
MySQL `SHOW CREATE TABLE` 命令返回的建表语句中,字段定义之间使用**字面量** `\n` 字符(两个字符:反斜杠 + n),而非真正的换行符。这会导致生成的 SQL 脚本格式异常,无法直接执行。
**示例:**
```sql
-- 错误格式(包含字面量 \n
CREATE TABLE `test` (
\n `id` int NOT NULL,\n `name` varchar(50),\n PRIMARY KEY (`id`)
)
```
**解决方案:**
在脚本中获取 `SHOW CREATE TABLE` 输出后,必须经过三步处理:
```bash
# 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`(两个字符)转换为真实换行符(一个字符)
```bash
# 注意转义:sed 中 \\n 匹配字面量 \n,\n 替换为真实换行
```
3. **`sed '1d;$d'`** - 删除第一行(`CREATE TABLE ... (`)和最后一行(`) ENGINE=...`),提取纯表体
```bash
# 替代失效的正则提取(sed 默认不跨行匹配)
# 1d = 删除第一行,$d = 删除最后一行
```
**已生成脚本的批量修复:**
如果脚本已生成但包含字面量 `\n`,使用以下命令批量修复:
```bash
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`
**格式:**
```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. 验证连接
```bash
# 验证源库连接(只读)
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. 获取表列表
从源数据库获取所有表:
```sql
SHOW TABLES FROM <source_database>;
```
### 5. 对比并生成脚本
对每个表执行:
#### 5.1 读取源表结构
```sql
SHOW CREATE TABLE <source_database>.<table_name>\G
```
#### 5.2 读取目标表结构
```sql
-- 检查表是否存在
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` |
**对比算法:**
```python
# 伪代码
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 脚本
**单表脚本格式:**
```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. 执行脚本
对每个生成的脚本:
```bash
# 执行单表脚本
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`
```markdown
## 表结构同步 - {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
```markdown
# 表结构同步脚本 - {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 | 初始版本 |