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 の列番号に一意性インデックスが指定されているため、注文番号が重複する可能性はありません。しかし、類似した関数が行に設定する別のデータベース用に書き込まれている可能性はあります。この場合、使用済みの列名が指定されます。
この関数は、表 orders のすべての行を走査するカーソルとして、scan_ord を宣言しています。このカーソルは FOR UPDATE 節で宣言されていますが、これは、カーソルがデータの変更に使用できることを示しています。カーソルが正しくオープンした場合は、この関数はトランザクションを開始し、表の各行を反復処理します。この関数は、表の各行について、埋込み SELECT 文を使用して、現在行と注文番号が同じ行が表に何行あるかを調べます。マルチユーザ環境のためのプログラミングで説明するように、この手順は、排他レベルが正しくないと失敗します。
デモンストレーション データベースでは、この表に一意性インデックスが付いているため、dup_cnt に戻されるカウント、つまり重複行の数は常に 1 です。この値が 1 よりも大きい場合は、この関数は表の現在行を削除して、カウント数を 1 減らします。
このような目的で使用される関数は、この例より高度な設計を必要とします。この関数は、データベース サーバが戻す最後の重複行以外のすべての重複行を削除します。この順番は、行の内容や意味とはまったく関係がありません。前出の例の関数は、カーソル宣言に ORDER BY 節を追加することで改善することができます。ただし、ORDER BY 節と FOR UPDATE 節を同時に使用することはできません。挿入の例で、より適切な方法を説明します。