case式を使って条件分岐するupdate文を試す

CASE式のススメ(後編)を読んで、update文でcase式を使って条件分岐するテクニックを知ってかなり感動しました。行ごとに異なる更新を1つのupdate文でできるのすごいですね。

今回はこの記事に書いてある、主キーを入れ替えるテクニックを少し応用してみたいと思います。

jQuery UIのsortableのようなリストの項目をドラッグ&ドロップで並び替えるUIがありますよね。そのデータをテーブルで管理しているとして、並び替えてデータを更新する時のupdate文を、case式を使って書いてみたいと思います。

テーブルはこんな感じ。Ordinalはリストの何番目の項目かを表す順序です。

create table #Sortable(
    Name nvarchar(5),
    Ordinal int,
    constraint UQ_Ordinal unique(Ordinal));

たとえば、テーブルにはこんなデータが入っていて、

Name  Ordinal
----- -----------
Item1 1
Item2 2
Item3 3
Item4 4
Item5 5

Item4をドラッグしてItem2のところにドロップすると、こんな風になるようにします。

Name Ordinal
----- -----------
Item1 1
Item4 2
Item2 3
Item3 4
Item5 5

ドロップした時に、Item4のOrdinalを2にして、Item2とItem3のOrdinalはそれぞれ1を加える訳なんですが、これを行うupdate文は次のように書けると思います。 @fromはドラッグ&ドロップで移動するItemのOrdinal、@toはドロップ先のOrdinalをパラメータとして渡します。上の例では@fromが4で@toが2を設定します。

update #Sortable
set Ordinal = case
    -- 移動するItem->移動先のOridnalを設定
    when Ordinal = @from then @to
    -- 移動元と移動先の間のItem
    when @to < @from then Ordinal + 1   -- 上方向への移動->Ordinalを+1
    else Ordinal - 1 end               -- 下方向への移動->Ordinalを-1
where
    -- 移動元と移動先の間にあるItemのみを対象
    Ordinal between (case when @to > @from then @from else @to end)
        and (case when @to > @from then @to else @from end)

うん、上手くいってるはず。

コード全体はこちら