使用游标删除

您还可使用游标编写 DELETE 语句来删除最后访存了的行。以此方式删除行允许您的程序基于在 WHERE 子句中不可测试的条件进行删除。由于设置事务的开始和结束的方式的缘故,下列示例仅适用于不符合 ANSI 的数据库
警告: 此示例中的 GBase 8s ESQL/C 函数的设计是不安全的。它依赖于正确的操作的当前隔离级别。该章节稍后讨论隔离级别。要获取关于隔离级别的更多信息,请参阅 对多用户环境编程。即使当该函数按期望的方式运行时,它的影响也依赖于表中行的物理顺序,这样做通常并不理想。
int delDupOrder()
            {
            int ord_num;
            int dup_cnt, ret_code;
            
            EXEC SQL declare scan_ord cursor for
            select order_num, order_date
            into :ord_num, :ord_date
            from orders for update;
            EXEC SQL open scan_ord;
            if (sqlca.sqlcode != 0) 
            return (sqlca.sqlcode);
            EXEC SQL begin work;
            for(;;)
            {
            EXEC SQL fetch next scan_ord;
            if (sqlca.sqlcode != 0) break;
            dup_cnt = 0; /* default in case of error */
            EXEC SQL select count(*) into dup_cnt from orders
            where order_num = :ord_num;
            if (dup_cnt > 1)
            {
            EXEC SQL delete from orders
            where current of scan_ord;
            if (sqlca.sqlcode != 0) 
            break;
            }
            } 
            ret_code = sqlca.sqlcode;
            if (ret_code == 100)             /* merely end of data */
            EXEC SQL commit work;
            else      /* error on fetch or on delete */
            EXEC SQL rollback work;
            return (ret_code);
            }

该函数的目的是删除包含重复的订单号码的行。实际上,在演示数据库中,orders.order_num 列有唯一约束,因此,其中不可出现重复的行。然而,可为另一数据库编写一个类似的函数;这一个使用熟悉的列名称。

该函数声明游标 scan_ord 来扫描 orders 表中的所有行。使用 FOR UPDATE 子句声明它,说明该游标可修改数据。如果该游标正确地打开,则该函数开始一个事务,然后对表的行进行循环。对于每一行,它使用嵌入式 SELECT 语句来确定该表的多少行具有当前行的订单编号。如果没有正确的隔离级别,此步骤失败,如 对多用户环境编程 描述的那样。)

在演示数据库中,使用它在此表上的唯一约束,返回到 dup_cnt 的计数始终为一。然而,如果它更大,则该函数删除表的当前行,将重复的计数减少一个。

有时需要这类清理函数,但它们一般需要更复杂的设计。此函数删除所有重复的行,除了数据库服务器返回的最后一行之外。那个顺序对这些行的内容及其含义没有任何关系。您或许可通过将 ORDER BY 子句添加到游标声明来提升前面例子中函数的性能。然而,您不可同时使用 ORDER BY 与 FOR UPDATE。插入示例 提供一种更好的方法。