web-dev-qa-db-ja.com

順序を維持しながら順序付きリストをデータベースに保存する最良の方法

過去数年間に何度も遭遇した問題に対して、誰かが良い解決策を持っているかどうか疑問に思いました。

私はショッピングカートを持っており、私の顧客は注文が重要であることを明示的に要求しています。そのため、注文をDBに永続化する必要があります。

明白な方法は、単に0からNまでの番号を割り当て、そのように並べ替えるOrderFieldを挿入することです。

しかし、これを行うと再注文が困難になり、このソリューションは多少壊れやすく、いつか私に戻ってくると思います。

(NHibernateとSQL Server 2005でC#3.5を使用しています)

ありがとうございました

67
Tigraine

FWIW、私はあなたが提案する方法(つまり、注文をデータベースにコミットする)は問題の悪い解決策ではないと思います。また、おそらくこれが最も安全で最も信頼できる方法だと思います。

24
Galwegian

ここで、このスレッドに沿って発生する誰にとってもこれを簡単にプログラミングするための私のソリューションです。トリックは、1回の更新で挿入/削除の上または下のすべての順序インデックスを更新できることです。

SQLクエリでサポートされている、テーブル内の数値(整数)列の使用

CREATE TABLE myitems (Myitem TEXT, id INTEGER PRIMARY KEY, orderindex NUMERIC);

Orderindex 6でアイテムを削除するには:

DELETE FROM myitems WHERE orderindex=6;    
UPDATE myitems SET orderindex = (orderindex - 1) WHERE orderindex > 6;

2つのアイテム(4と7)を交換するには:

UPDATE myitems SET orderindex = 0 WHERE orderindex = 4;
UPDATE myitems SET orderindex = 4 WHERE orderindex = 7;
UPDATE myitems SET orderindex = 7 WHERE orderindex = 0;

つまり、0は使用されないので、あいまいなアイテムを持たないように、それをダミーとして使用します。

3に挿入するには:

 UPDATE myitems SET orderindex = (orderindex + 1) WHERE orderindex > 2;
 INSERT INTO myitems (Myitem,orderindex) values ("MytxtitemHere",3)
48
Kickaha

最善の解決策は 二重リンクリスト です。 O(1)インデックス作成を除くすべての操作に対して。必要なアイテムのwhere句を除いて、SQLにすばやくインデックスを付けることはできません。

0、10、20タイプは失敗します。シーケンス列1は失敗します。グループの移動時にフロートシーケンス列が失敗する。

二重リンクリストは、追加、削除、グループの削除、グループの追加、グループの移動と同じ操作です。単一のリンクリストでも問題ありません。しかし、私の考えでは、SQLの方がダブルリンクの方が適しています。単一のリンクリストでは、リスト全体が必要です。

31
sean wagner

リンクリストの実装を使用するのはどうですか? 1つの列があると、次のアイテムの値(注文番号)が保持されます。間にオーダーを挿入するときに使用するのがはるかに簡単だと思います。番号を付け直す必要はありません。

10
Js.

残念ながら、これに対する特効薬はありません。 SELECTステートメントの順序は、order by句なしでは保証できません。列を追加し、その周りにプログラムする必要があります。

リストのサイズとサイトのヒットに応じて、順序シーケンスにギャップを追加することをお勧めすることを知りません。すべてのギャップが使い果たされた場合に対応するため)。私はこれがあなたの状況であなたにどんな利益を与えるかを見るために詳しく調べます。

申し訳ありませんが、これ以上は提供できません。これが役に立てば幸いです。

5
Binary Worrier

A、AA、B、BA、BBのアプローチはお勧めしません。階層を決定するために多くの追加の処理が必要であり、その間にエントリを挿入することはまったく楽しいものではありません。

OrderField、整数を追加するだけです。ギャップを使用しないでください。次の中間挿入で非標準の「ステップ」を使用する必要があるか、リストを再同期してから新しいエントリを追加する必要があるためです。

0 ... Nを指定すると並べ替えが簡単です。SQLの外部でArrayメソッドまたはListメソッドを使用してコレクション全体を並べ替えることができる場合は、各エントリを更新するか、挿入先を特定できます。それに応じて、その前後の各エントリに+1または-1。

小さなライブラリを作成したら、それは簡単なものになります。

4
Adam

私はそれを解決しましたプラグマチックこのように:

  1. 順序はUIで定義されます。

  2. バックエンドは、リスト内のすべてのアイテムのIDと対応する位置を含むPOSTリクエストを取得します。

  3. トランザクションを開始し、IDごとにポジションを更新します。

完了

そのため、注文は高価ですが、注文リストを読むのは非常に安価です。

1
Bijan

注文フィールドを挿入します。その最も簡単な方法。顧客がフィールドを再注文できる場合、または途中で挿入する必要がある場合は、そのバッチ内のすべてのアイテムの注文フィールドを書き換えます。

将来的には、挿入と更新のパフォーマンスが低いためにこの制限が見られる場合、整数ではなくvarcharフィールドを使用することが可能です。これにより、挿入時に非常に高いレベルの精度が可能になります。たとえば、アイテム「A」と「B」の間に挿入するには、「AA」として注文されたアイテムを挿入できます。これは、ほとんどの場合、ショッピングカートにとってはやり過ぎです。

1
Jack Ryan

カートアイテムの上の抽象化のレベルでは、CartOrder(たとえば、CartItemで1-nを持っている)と言う項目を維持できます。それを解析し、それに応じてアイテムモデルを配置する必要があるのは、アプリケーションレイヤーです。このアプローチの大きなプラスは、注文の入れ替えの場合です。個々のオブジェクトに変更はないかもしれませんが、注文は注文アイテムテーブルの行内のインデックスフィールドとして永続化されるため、それぞれに対して更新コマンドを発行する必要があります。インデックスフィールドを更新する行。このアプローチに対するあなたの批判を教えてください。これがどのように失敗するのか知りたいです。

1
redzedi

注文番号のギャップを維持することをお勧めします。したがって、1、2、3などの代わりに、10、20、30を使用します... 1つ以上のアイテムを挿入する必要がある場合は、すべてを再注文するのではなく、15に配置できます。その時点で。

0
harriyott

まあ、私は短い答えは次のとおりです:

Cartcontentsテーブルに自動識別の主キーを作成し、正しいトップダウンの順序で行を挿入します。次に、主キーの自動識別列による順序でテーブルから選択すると、同じリストが表示されます。これを行うと、カートの内容が変更された場合に備えて、すべてのアイテムを削除して再挿入する必要があります。 (しかし、それはまだそれを行うにはかなりきれいな方法です)それが実行可能でない場合は、他の人が提案したような注文列に進んでください。

0
sindre j