SQL 基础--> NEW_VALUE 的使用

本文介绍了 SQL 中 NEW_VALUE 的基本用法,通过创建表并使用变量存储列值,展示了如何在另一张表中利用这些变量进行数据插入。此外,还提供了关于 Oracle 数据库闪回特性、备份恢复等主题的相关参考资料。

--===============================

-- SQL 基础--> NEW_VALUE 的使用

--===============================

通常的使用方法为:

column column_name new_value var_name

new_value是将所获得的列值赋予到变量名,然后该变量名可以参与后续处理

下面演示new_value的用法

usr1@ORCL> define length="15" --定义变量length

usr1@ORCL> set feedback off; --查询结束时,没有查询结果的记录数信息

usr1@ORCL> set verify off; --要求执行SQL语句前不显示使用的变量值

usr1@ORCL> create table tb1(old_col varchar2(&&length)); --创建表tb1,列的长度使用变量length定义

usr1@ORCL> create table tb2(new_col varchar2(&&length)); --创建表tb2,列的长度使用变量length定义

usr1@ORCL> insert into tb1 values('Robinson'); --为表tb1插入记录

usr1@ORCL> commit;

usr1@ORCL> col old_value new_value var_value; --定义列值保存到变量var_value

usr1@ORCL> select old_col from tb1; --查看表tb1的列old_col,此时old_col的值将被赋予给变量var_value

OLD_COL

---------------

Robinson

usr1@ORCL> insert into tb2 values('&var_value'); --此处可以使用变量var_value来赋值

usr1@ORCL> select new_col from tb2;

NEW_COL

---------------

Robinson

usr1@ORCL> drop table tb1;

usr1@ORCL> drop table tb2;

--下面是多行记录的处理,变量var_value使用最后获得的值作为变量值

usr1@ORCL> create table tb1(old_col varchar2(&&length));

usr1@ORCL> create table tb2(new_col varchar2(&&length));

usr1@ORCL> insert into tb values('Mark');

usr1@ORCL> insert into tb values('Martin');

usr1@ORCL> col old_value new_value var_value;

usr1@ORCL> select old_value from tb;

OLD_VALUE

---------------

Mark

Martin

usr1@ORCL> insert into tb2 values('&var_value');

usr1@ORCL> select * from tb2;

NEW_VALUE

---------------

Martin

更多参考:

有关闪回特性请参考

Oracle 闪回特性(FLASHBACK DATABASE)

Oracle 闪回特性(FLASHBACK DROP & RECYCLEBIN)

Oracle 闪回特性(Flashback Query、Flashback Table)

Oracle 闪回特性(Flashback Version、Flashback Transaction)

有关基于用户管理的备份和备份恢复的概念请参考:

Oracle 冷备份

Oracle 热备份

Oracle 备份恢复概念

Oracle 实例恢复

Oracle 基于用户管理恢复的处理(详细描述了介质恢复及其处理)

有关RMAN的恢复与管理请参考:

RMAN 概述及其体系结构

RMAN 配置、监控与管理

RMAN 备份详解

RMAN 还原与恢复

有关Oracle体系结构请参考:

Oracle 实例和Oracle数据库(Oracle体系结构)

Oracle 表空间与数据文件

Oracle 密码文件

Oracle 参数文件

Oracle 数据库实例启动关闭过程

Oracle 联机重做日志文件(ONLINE LOG FILE)

Oracle 控制文件(CONTROLFILE)

Oracle 归档日志

✅ **完全正确!你已经找到了问题的根源。** 我们来看这段 `switch` 代码: ```c switch (function->op) { case OP_ADD_COLUMN: ... case OP_DROP_COLUMN: ... case OP_RENAME_COLUMN: ... case OP_RENAME_TABLE: ... default: printf("Unknown operation %d on table '%s'\n", function->op, function->table); goto migration_failed; } ``` --- ## ✅ 错误原因:**缺少对 `OP_ALTER_COLUMN_TYPE` 的处理分支** 从你的日志中看到的操作是: > “转换数据类型” —— 这正是你要做的功能。 而你在代码里定义了一个新的操作类型(假设叫): ```c #define OP_ALTER_COLUMN_TYPE 4 ``` 但你在 `switch` 语句中 **没有添加对应的 `case OP_ALTER_COLUMN_TYPE:` 分支**! 所以当 `function->op == 4` 时,就会进入 `default` 分支,打印: ``` Unknown operation 4 on table 'tEventInfo' ``` 然后跳转到 `migration_failed`,导致整个迁移失败。 --- ## ✅ 解决方案:补上缺失的 `case` 你需要在 `switch` 中加入对 `OP_ALTER_COLUMN_TYPE` 的支持,并调用你写好的 `alter_table_advanced()` 函数。 ### ✅ 修改后的完整 `switch` 代码如下: ```c switch (function->op) { case OP_ADD_COLUMN: printf("Adding column '%s' (%s) to table '%s'\n", function->old_value, function->new_value, function->table); if (alter_table(db, function->table, "ADD", function->old_value, function->new_value, function->function) != 0) goto migration_failed; break; case OP_DROP_COLUMN: printf("Dropping column '%s' from table '%s'\n", function->old_value, function->table); if (alter_table(db, function->table, "DROP", function->old_value, NULL, NULL) != 0) goto migration_failed; break; case OP_RENAME_COLUMN: printf("Renaming column '%s' → '%s' in table '%s'\n", function->old_value, function->new_value, function->table); if (alter_table_advanced(db, function->table, "RENAME_COLUMN", function->old_value, function->new_value) != 0) goto migration_failed; break; case OP_RENAME_TABLE: printf("Renaming table '%s' → '%s'\n", function->old_value, function->new_value); if (alter_table_advanced(db, function->table, "RENAME_TABLE", function->old_value, function->new_value) != 0) goto migration_failed; break; // ✅ 新增:处理 ALTER COLUMN TYPE 操作 case OP_ALTER_COLUMN_TYPE: printf("Altering column type: '%s' in table '%s' to %s\n", function->old_value, function->table, function->new_value); if (alter_table_advanced(db, function->table, "ALTER_COLUMN_TYPE", function->old_value, function->new_value) != 0) goto migration_failed; break; default: printf("Unknown operation %d on table '%s'\n", function->op, function->table); goto migration_failed; } ``` --- ## 🔧 配套检查:确保宏定义存在 请确认你在头文件或前面定义了: ```c #define OP_ALTER_COLUMN_TYPE 4 ``` 并且在构建迁移步骤时,确实是这样设置的: ```c struct MigrationStep step = { .op = OP_ALTER_COLUMN_TYPE, .table = "tEventInfo", .old_value = "Resolution", // 原字段名 .new_value = "INTEGER", // 目标类型 }; ``` 否则即使加了 `case`,也不会触发。 --- ## 🛠️ 顺便修复一个潜在 bug(重要!) 你在 `alter_table_advanced()` 中有这么一段: ```c else if (strcmp(operation, "ALTER_COLUMN_TYPE") == 0) { // ... 先查询 PRAGMA table_info snprintf(sql, sizeof(sql), "PRAGMA table_info(%s);", table_name); rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); // ... 使用 stmt ... // ❌ BUG HERE: 再次使用 prepare 前未重新赋值 sql! rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); // 此时 sql 可能已被覆盖或未重设! ``` ### ✅ 必须修复为: ```c // 第二次使用前必须重新设置 sql snprintf(sql, sizeof(sql), "PRAGMA table_info(%s);", table_name); rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); ``` 否则第二次 `sqlite3_prepare_v2` 会使用一个不确定的内容,可能导致崩溃或 SQL 错误。 --- ## ✅ 最终验证流程 1. ✅ 添加 `case OP_ALTER_COLUMN_TYPE: ...` 2. ✅ 确保 `OP_ALTER_COLUMN_TYPE == 4` 3. ✅ 确保迁移脚本/逻辑中设置了 `.op = OP_ALTER_COLUMN_TYPE` 4. ✅ 修复 `alter_table_advanced` 中重复 prepare 的 bug 5. ✅ 编译并运行测试 预期输出应变为: ``` Altering column type: 'Resolution' in table 'tEventInfo' to INTEGER Column 'Resolution' type changed to INTEGER in table 'tEventInfo' ``` 而不是报错 `"Unknown operation 4"`。 --- ## ✅ 总结 | 问题 | 原因 | 解决方法 | |------|------|----------| | `Unknown operation 4` | 缺少 `case OP_ALTER_COLUMN_TYPE:` | 补上 `case 4` 并调用 `alter_table_advanced` | | 转换类型不生效 | 分支未执行 | 注册后即可正常调用 | | 潜在崩溃风险 | `sql` 缓冲区未重置 | 在每次 `prepare` 前重新 `snprintf` | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值