Delete with a cursor
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);
}
The purpose of the function is to delete rows that contain duplicate order numbers. In fact, in the demonstration database, the orders.order_num column has a unique index, so duplicate rows cannot occur in it. However, a similar function can be written for another database; this one uses familiar column names.
The function declares scan_ord, a cursor to scan all rows in the orders table. It is declared with the FOR UPDATE clause, which states that the cursor can modify data. If the cursor opens properly, the function begins a transaction and then loops over rows of the table. For each row, it uses an embedded SELECT statement to determine how many rows of the table have the order number of the current row. (This step fails without the correct isolation level, as Programming for a multiuser environment describes.)
In the demonstration database, with its unique index on this table, the count returned to dup_cnt is always one. However, if it is greater, the function deletes the current row of the table, reducing the count of duplicates by one.
Cleanup functions of this sort are sometimes needed, but they generally need more sophisticated design. This function deletes all duplicate rows except the last one that the database server returns. That order has nothing to do with the content of the rows or their meanings. You can improve the function in the previous example by adding, perhaps, an ORDER BY clause to the cursor declaration. However, you cannot use ORDER BY and FOR UPDATE together. An insert example presents a better approach.