Category5 を優先度 5 から優先度 1 に移動するよりも、より一般的なケースに対処しましょう。2 つの (鏡像の) より良い例があります。
- カテゴリ 4 を優先度 2 に移動します。
- カテゴリ 2 を優先度 4 に移動します。
これらのケースのそれぞれで、2 つの影響を受けない行 (優先度 1 と 5 の行)、移動として指定された 1 つの行、および「巻き添え被害」として影響を受けた 2 つの行があります。
UPDATE ステートメントのトリックのほとんどは、「前」の状態から「後」の状態の正しいデータを生成する SELECT ステートメントを作成することです。もう 1 つのトリックは、操作を制御するパラメーターを特定することです。ここでは、次の 2 つのパラメーターがあります。
- カテゴリ (名前) — または同等のカテゴリ ID 番号。
- カテゴリの新しい優先度。
「上に移動」(優先度の低いカテゴリを優先度の高いカテゴリに移動) と「下に移動」(優先度の高いカテゴリを優先度の低いカテゴリに移動) には、別々のアルゴリズムが必要になる場合があります。
前後のシナリオを以下に示します。
Before Category4 to Priority 2 Category2 to Priority 4
======================== ======================== ========================
| Category | Priority | | Category | Priority | | Category | Priority |
======================== ======================== ========================
| Category1 | 1 | | Category1 | 1 | | Category1 | 1 |
| Category2 | 2 | | Category4 | 2 | | Category3 | 2 |
| Category3 | 3 | | Category2 | 3 | | Category4 | 3 |
| Category4 | 4 | | Category3 | 4 | | Category2 | 4 |
| Category5 | 5 | | Category5 | 5 | | Category5 | 5 |
======================== ======================== ========================
最初に「上に移動」アルゴリズムを試してみましょう。
上に移動
TDQD (Test-Driven Query Development) を使用すると、段階的にリストを生成できます。
高優先度で影響を受けない行:
SELECT cat_id, category, priority
FROM categories
WHERE priority < 2;
低優先度で影響を受けない行:
SELECT cat_id, category, priority
FROM categories
WHERE priority > (SELECT priority FROM categories WHERE category = 'Category4');
移動される行:
SELECT cat_id, category, 2 AS priority
FROM categories
WHERE category = 'Category4';
優先度を調整する必要がある行:
SELECT cat_id, category, priority + 1 AS priority
FROM categories
WHERE priority >= 2
AND priority < (SELECT priority FROM categories WHERE category = 'Category4');
明らかに、これら 4 つのクエリを 4 方向の UNION を介して組み合わせて、完全な新しい順序付けを生成できます。同様に明らかに、クエリ 1 と 2 は変更されない行を選択するため、クエリ 3 と 4 によって生成された、変更される行のみを処理する必要があります。
したがって、変更された行は次のとおりです。
SELECT cat_id, category, 2 AS priority
FROM categories
WHERE category = 'Category4'
UNION
SELECT cat_id, category, priority + 1 AS priority
FROM categories
WHERE priority >= 2
AND priority < (SELECT priority FROM categories WHERE category = 'Category4');
ここで、優先度を変更する UPDATE ステートメントを派生させる必要があります (カテゴリ ID またはカテゴリ名を変更する必要はありません)。
UPDATE categories
SET priority =
(SELECT x.priority
FROM (SELECT cat_id, 2 AS priority
FROM categories
WHERE category = 'Category4'
UNION
SELECT cat_id, priority + 1 AS priority
FROM categories
WHERE priority >= 2
AND priority < (SELECT priority FROM categories WHERE category = 'Category4')
) AS x
WHERE x.cat_id = categories.cat_id
)
WHERE cat_id IN
(SELECT cat_id
FROM categories
WHERE category = 'Category4'
UNION
SELECT cat_id
FROM categories
WHERE priority >= 2
AND priority < (SELECT priority FROM categories WHERE category = 'Category4')
);
メインの UPDATE ステートメントの WHERE 句を簡略化すると、次のようになります。
UPDATE categories
SET priority =
(SELECT x.priority
FROM (SELECT cat_id, 2 AS priority
FROM categories
WHERE category = 'Category4'
UNION
SELECT cat_id, priority + 1 AS priority
FROM categories
WHERE priority >= 2
AND priority < (SELECT priority FROM categories WHERE category = 'Category4')
) AS x
WHERE x.cat_id = categories.cat_id
)
WHERE cat_id IN
(SELECT cat_id
FROM categories
WHERE priority >= 2
AND priority <= (SELECT priority FROM categories WHERE category = 'Category4')
);
これは、Mac OS X 10.7.4 で実行されている IBM Informix Dynamic Server 11.70.FC2 に対してテストしたときに正しい答えを生成しました。
下に移動
「Move Down」の並列分析により、UPDATE ステートメントが生成されます。
UPDATE categories
SET priority =
(SELECT x.priority
FROM (SELECT cat_id, 4 AS priority
FROM categories
WHERE category = 'Category2'
UNION
SELECT cat_id, priority - 1 AS priority
FROM categories
WHERE priority <= 4
AND priority > (SELECT priority FROM categories WHERE category = 'Category2')
) AS x
WHERE x.cat_id = categories.cat_id
)
WHERE cat_id IN
(SELECT cat_id
FROM categories
WHERE priority <= 4
AND priority >= (SELECT priority FROM categories WHERE category = 'Category2')
);
マグナムオーパス
最終的な答えは、これらのクエリを組み合わせて、名前付きカテゴリが上下に移動したかどうかに関係なく機能するようにします (カテゴリが同じ場所に留まるように指定されている場合は何もしません)。そのようなクエリが開発できることに疑いの余地はありませんが、それに伴う労力に見合う価値があるとは思いません。カテゴリ名とカテゴリの新しい優先度を取得するストアド プロシージャを作成すると、必要な UPDATE ステートメントが実行されます。これは、UI (Web ブラウザーまたはより密接に結合されたもの) から簡単に実行できます。上記の内容は十分に複雑ですが、説明可能です。そして「説明可能」とは、それが「保守可能」である可能性もあるということです。