レコードを並べ替えてDBに保存できるようにする必要があります(MS SQLを使用していますが、問題ではないようです)。私は可能な2つの解決策を見ます:
{「一意キー制約 'IX_EscortItems'の違反。オブジェクト 'dbo.EscortItems'に重複キーを挿入できません。重複キーの値は(2、20)です。\ r\nステートメントが終了しました。 "}
この問題を解決するための正しいアプローチは何ですか?
使用できるアプローチは複数あります。
UNIQUE
制約を無視することです。その後、最終的にデータベースが再び整合性を保つようにするのはソフトウェア次第です。ギャップのあるシーケンス番号を使用します。
最初に10、20、30などのシーケンス番号から始める場合は、すでに指定されているシーケンス番号の間にシーケンス番号を割り当てることで、それらを並べ替えることができます。
たとえば、4番目の要素を最初と2番目の要素の間に配置すると、シーケンス番号は10、15、20、30、50などになります。
要素を配置するためにギャップがなくなるのを回避するには、シーケンス番号を定期的に正規化するか、浮動小数点シーケンス番号を使用できます。
あなたのための4つのオプション。私はオプション4が好きですが、最初のものが最も簡単です。
Order
列の値は重要ではなく、それらの相対値のみです。 1から10、11から20、または57から66の10行に番号を付けるかどうかはすべて同じです。
したがって、非常に簡単な解決策は、最も高いOrder
列よりも1つ上から開始することです。行にOrder
の値が1〜10あり、それらを逆にする必要がある場合は、 20から11。
それらは正しくソートされ、個別の値の範囲にあるため、一意性違反はありません。
これの欠点は、リスト全体をやり直したくなく、2つの値を交換したいだけの場合は少しトリッキーです。
1つの列Order
を追加する代わりに、2つの列SortOrder
とSortVersion
を追加します。これら2つの列の組み合わせに一意性制約を適用します。
リスト内のアイテムを並べ替える場合は、SortVersion
の新しい値を保存するときに、SortVersion
列を1つ増やします。
使用しているフレームワークによっては、レコードをドメインオブジェクトとしてアプリケーション層に格納するため、これが最も簡単なオプションとなる場合があります。拭き取り、必要な順序で挿入し直してください。
これは、EFを使用していない場合、またはカスケード削除を引き起こすFK関係がある場合は、実行できない可能性があります。
技術的に言えば、これは最も正規化されたオプションです。ソート順はおそらくエンティティの属性ではなく、エンティティと他のエンティティ間の関係の属性だからです。したがって、Order
は実際には3NFに違反しています。信じられないかもしれませんが、列の値はキー(1NF)、キー全体(2NF)、および何もない主キー(3NF)に依存する必要があります)、この場合、Order
列は、より大きなコンテキスト内のエンティティの関係に依存します。これを正規化するには、結合テーブルが必要です。
したがって、請求書テーブルとline_itemテーブルがあるとします。 3番目のテーブル、InvoiceID
、LineItemID
、およびSortOrder
を含むinvoice_line_itemテーブルを追加します。行の順序を変更する場合は、行をすべて削除してから、再度挿入してください。これにより、FKまたは関連オブジェクトの問題が回避されます。これらのFKはこの3番目のテーブルではなく、他のテーブルの1つにあるためです。これは、明細と請求書の関係を変更することになるので、それらを削除して置き換えることは理にかなっています。当然、すべてをトランザクションでラップする必要があります。
一意の制約は、Order列の組み合わせである必要がありますand親テーブルへの外部キー。例として「ショッピングカート」を使用します。
Table: ShoppingCartItems
- ShoppingCartId (FK to ShoppingCarts table)
- DisplayNumber (int)
この場合、一意の制約により、ShoppingCartItems.ShoppingCartId
とShoppingCartItems.DisplayNumber
の組み合わせがテーブル内で一意になるため、ショッピングカートに同じ表示順序で複数のアイテムを含めることはできません。
一時的に負の値を使用します
declare int @rowA = 7
declare int @rowB = 22
update table set order = -@rowB where order = @rowA;
update table set order = @rowA where order = @rowB;
update table set order = @rowB where order = -@rowB;
あなたはそれをトランザクションにラップすることができますが、ほとんどの場合あなたは衝突を起こすことはないでしょう
3つの提案:
sort_key
、ordinal
またはおそらくposition
。RubyでのActive Recordのオープンソース実装があなたに刺激を与えるかもしれません。 acts_as_list gem のソースを読んで、これらのアイデアと比較してください。
リレーショナルデータベース全般の基本的な考え方の1つは、データベース自体のレコードには「固有の」順序がないということです。1。
順序付けは通常、クエリの結果に課せられます。この場合、項目を表示する順序を指定する列を決定し、それに応じて結果を順序付けることができます。
たとえば、各注文の日付/時刻のいずれかで注文のレポートを作成できるようにしたい場合があります(つまり、注文された順に表示します)。
select ID, value, date /* , ... */ from Orders
order by ship_date
...または注文が発送された日時
select ID, value, date /* , ... */ from Orders
order by ship_date
...またはおそらくサイズの降順(最大の注文がいつ発生したかに関係なくすばやく確認できるようにするため)。
select ID, value, date /* , ... */ from Orders
order by value desc
もちろん、order_by
列(必要に応じて別の名前で)完全に任意の順序で(または、少なくともデータベースに格納されていない基準に基づいて)順序で表示する場合。この場合、並べ替えを行うときに、いくつかの選択肢があります。 1つは、この列に一意の値が含まれていることをデータベースに通知しないことです。もう1つは、単に重複を避けることです。たとえば、1と2の番号が付いたレコードから始めたとします。それらを逆にするには、番号をそれぞれ4と3に変更します。
これをプログラムで実行するには、現在列にある最大値を見つけます2、次に並べ替えるときに、それより大きい値をベース値として使用します。また、現在使用されている最小値を確認することもできます。レコード数よりも大きい場合は、0から番号付けをやり直すことができます。
1. MS SQLには「クラスター化インデックス」の概念がありますが、これはレコードが格納される順序に直接関連しています-これは基本的には最適化です。 2.通常はこの列にインデックスを付けるので、この操作は非常に高速であると予想できます。
多くの場合、注文列を使用する場合、重要なのは特定の値ではなく注文自体です。したがって、順序列を使用する場合、それらが互いに相対的に正しくソートされている限り、その列の番号が何であるかを気にする必要はありません。
したがって、レコードを順番に上に移動したい場合は、次のことができます。
競合なし
さらに図解。注文値がある場合:
1,2,3,4,5,6,7,8
#7のアイテムを#3に移動するには、まず次のような更新を実行します
update foo set order = order +1 where container = X and order >=3
これはあなたに与えます
1,2,4,5,6,7,8,9
次に、移動する特定のアイテムの注文値を設定します
update foo set order = 3 where id = 102334
そして、あなたは終わるかもしれません
1,2,3,4,5,6,7,9
他のタイプの再配置についても、同様のパターンに従います。
これは明らかに、小さめのサイズまたは中程度のサイズのセットを扱う場合に最適です。特定の順序で15,000,000のレコードがある場合、おそらく他のアプローチの1つを使用する必要があります。
ここで、要件をより深く掘り下げ、実装についてあまり気にしないでください。それはそれ自体を処理します。それを行うためのより良い方法はありません。
並べ替える一意の番号があるかどうか、本当に気になる人はいますか?ユーザーとして(これを手動で実行していると仮定して)、それらがすべてゼロであるかどうか気にしない場合はどうなりますか?不注意で重複が含まれていると思われ、その順序がインターフェースに表示されているものと一致すると想定している場合は、いつでも警告を投稿できます。繰り返しになりますが、請求システムのように、この一意でソートされた番号の要件はありますか(これらの番号のギャップを許容しないドイツの会社のシステムに取り組んだことを思い出します)。
ソートを実行するための非常に複雑で時間のかかるアルゴリズムがあり、パフォーマンスの目的でこの値を保存したい場合は、データベースの制約を気にする必要がありますか?コードで処理します。
ユーザーがドロップダウンリストで優先する並べ替えを設定できるシステムを使用しています。管理者が番号を割り当て、それを機能させるだけです。重複のトラッピングはそれだけの価値はありません。