none
datagridviewから値入力時の重複値チェック方法について RRS feed

  • 質問

  • よろしくお願いいたします。

    [サーバー]:OS Windows Server 2003 Std + SQL Server 2008 r2

    [クライアント]:VS C# 2010 pro + Windows 7 pro

    複数のPCでFormのdatagridviewにてDBの値を表示・編集しています。

    内容は

    r_id IDENTITY

    id int

    results DATETIME

    n_id int

    s_id int

    time_stamp DATETIME

    です。

    操作の流れとしては

    フォームに設置したコンボボックスcmb_n_idで番号(n_id)を選ぶ

    するとリレーションされた同じくフォームに設置したコンボボックスcmb_s_idで番号(s_id)を選ぶ

    番号n_idとs_id絞り込まれて抽出されたレコードが一覧表示される

    新規入力なら

    id に番号を入力

    results に時間を入力

    更新なら

    既存のidのresultsカラムの値を書き換えて

    更新ボタンを押すと反映されるという仕組みです。

     

    ここで問題なのですが、新規入力の際、idに値を入力する時に

    重複する番号があればなんらかの方法で警告なり処理を止めるか戻すなりしたいのですが

    DBのトリガなどでINSERT時にチェックさせるようにすればと考えましたが、それだと更新ボタンを押すまで反映というこの構造では

    間違って同じidを新規入力していれば、更新に失敗するのではと考えました。

    1レコードの場合ならまだしも何百レコードの場合もあることから、このような動作では更新そのものが失敗するので

    また一から再度入力しなければならないのかと思いました。

    このような場合、idカラムの入力時にselect count(id) ... のようなクエリを走らせ値が1以上ならエラーを返し、0ならINSERT INTO...という

    方法でチェックするという方法なのでしょうか?それともこんな方法ではない定石があるのでしょうか?

    どなたかご指導お願いします。

     

     

     

     


    • 編集済み oira3ryu 2011年6月12日 2:25 タイトルから内容が分かりずらかったため
    2011年6月11日 14:35

回答

  • ユーザーがidを入力するのであれば、実際にデータベースに保存するまで重複するかどうかはわかりません。よって、失敗する可能性は常に残るということです。失敗した時にどう扱うかはアプリケーションの仕様によります。何百と更新する場合、一つでも登録に失敗すれば全ての登録を取り消すか、登録できたものはそのまま登録するということも考えられます。
    idをユーザーが入力するのではなく、自動的にサーバーで採番すれば上記のことは避けられます。採番は「日付+その日のシーケンス番号」などとすることもできます。例えば、r_idをサロゲートキーとし、idを伝票番号などと自動的に採番する方法です。
    いずれにしてもこの辺りはアプリケーションの仕様によって変わってきます。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク 山本春海 2011年7月1日 2:45
    2011年6月11日 15:32
    モデレータ

すべての返信

  • 新規登録しようとした ID がすでに登録されていた場合、どう振る舞ってほしいのですか?

    それと質問のタイトルは内容を簡潔に表す表現にしてくださいね。


    2011年6月11日 15:31
  • ユーザーがidを入力するのであれば、実際にデータベースに保存するまで重複するかどうかはわかりません。よって、失敗する可能性は常に残るということです。失敗した時にどう扱うかはアプリケーションの仕様によります。何百と更新する場合、一つでも登録に失敗すれば全ての登録を取り消すか、登録できたものはそのまま登録するということも考えられます。
    idをユーザーが入力するのではなく、自動的にサーバーで採番すれば上記のことは避けられます。採番は「日付+その日のシーケンス番号」などとすることもできます。例えば、r_idをサロゲートキーとし、idを伝票番号などと自動的に採番する方法です。
    いずれにしてもこの辺りはアプリケーションの仕様によって変わってきます。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    • 回答としてマーク 山本春海 2011年7月1日 2:45
    2011年6月11日 15:32
    モデレータ
  • trapemiyaさま、いつもお世話になります。

    マラソンの記録をとるDBアプリを作成していましたが、いろいろと問題が発生していて

    今回の質問もその一つです。

    r_idは、ご指摘の通りサロゲートキーとしているもので

    idには個々の選手のゼッケン番号(n_id毎、s_id毎に一意)の数値を入力していきます。

    r_id  |  id  |   results   | n_id  | s_id | time_stamp 

        1 | 131 | 04:38:51 |    10  |    4 | 2010/06/05 10:38:51....

        2 |   27 | 04:38:53 |    10  |    4 | 2010/06/05 10:38:53....

    ~  省略  ~

     926 | 306 | 07:05:01 |    10  |    9 | 2010/06/05 13:05:01....

    927  |  27 | 07:05:59 |    10  |     9 | 2010/06/05 13:05:59....

    ~  省略  ~

    3876 |157 | 05:21:00 |     11 |     4 | 2011/06/05 11:21:00....

    3877 |  11 | 05:21:21 |     11 |     4 | 2011/06/05 11:21:21....

    id列には、あらかじめ選手の登録数だけはわかるので、数値の範囲はわかるものの

    どの選手(id)が何番目に入ってくるかわからないのです。

    出走時点でキャンセルやリタイヤ等も考えられるのでidは必ずしも連番ではない(歯抜けあり)うえ

    同一n_id(グループ中)でさらに同一s_id(グループの中)ではidは一意でなくてはならないので

    このid列でIDENTITYのような仕組みを使えれば良いのでしょうが、それもできないので

    今回、事前に重複idではないかをチェックする仕組みを実装できるのなら

    「一つでも登録に失敗すれば全ての登録を取り消す」ことが無いようにできるのかな?と考えたのですが...

     

    2011年6月12日 2:10
  • galacoさま、ありがとうございます。

    新規登録しようとしたidが登録されていた場合は、datagridview上でmessageboxを出し

    「そのidはすでに登録されています」

    OKを押したらそのidを選択状態にして再入力を促すような処理を考えていましたが

    trapemiyaさんのご指摘にもありますように更新の仕組み等でも問題部分があり

    頓挫している状態です。

     

    (タイトルのご指摘ありがとうございます。変更したいと思います。)

     

    2011年6月12日 2:19
  • マラソンの続きだったのですね。
    今回、事前に重複idではないかをチェックする仕組みを実装できるのなら

    「一つでも登録に失敗すれば全ての登録を取り消す」ことが無いようにできるのかな?と考えたのですが...

    おそらくTableAdapterもしくはSqlDataAdapterを利用されていると思います。DataGridViewの各行の更新は、各行ごとにSQLが発行されて処理されます。つまり、各行が独立して更新されるわけです。よって、トランザクションを切らなければ、更新に失敗した行以外はデータベースに保存されます。

    さて、DataGridViewの全ての行を一括で更新する場合、RowUpdatingイベント、もしくはRowUpdatedイベントが役に立ちます。まずは以下を読んでみてください。

    DataAdapter のイベント処理 (ADO.NET)
    http://msdn.microsoft.com/ja-jp/library/6d1wk41s(v=VS.100).aspx

    #TableAdapterをご使用の場合は、そのAdapterプロパティでSqlDataAdapterを取得することができます。

    なお、DataGridViewの全ての行を一括で更新する前に、DataGridView上で同じidが重複して登録されていないかをチェックされると良いと思います。もし最初に入力した方のidが誤っていた場合、誤ったidがデータベースに保存されてしまうからです。
    #「一つでも登録に失敗すれば全ての登録を取り消す」という方針であれば、このようなチェックは必要ありません。個人的にはこちらの方がわかりやすいのではないかと思います。エラーが発生したとしてもDataGridViewには入力されたデータはそのまま残っていますし、エラーのあった行をエラーがあったことがわかるように表示されていますので、そこを修正してもう一度登録を試みるだけです。そのようにされる場合は、TransactionScopeを用いてトランザクションを切ってください。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年6月12日 6:15
    モデレータ