auto: sync OpenClaw config 2026-08-14 17:17

This commit is contained in:
2026-08-14 17:17:05 +08:00
parent d6da0db3d4
commit 7c4fe5a371
28 changed files with 2774 additions and 5 deletions
+482
View File
@@ -0,0 +1,482 @@
# 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 | 初始版本 |