DOBON.NET DOBON.NETプログラミング掲示板過去ログ

重複データ追加の回避方法は?

環境/言語:[Windows2000 VB.NET]
分類:[.NET]

 こんばんは。
今、SQLのAテーブルからデータを読み込み、ListViewで表示、選択した行をBテーブルへ追加・・・とします。ちなみに、AとBのテーブルのレイアウトは違います。月1回の締め日まで、どんどんBテーブルに追加のみです。

SQL += "insert into Bテーブル (○○区分,△△コード・・・
で追加していますが、同じKEYレコードを追加しようとした時にエラー回避するには、同じKEYのデータがBテーブルにないかどうかあらかじめ検索するのか、または、Insertする時にダメな時は何かコードが返ってくるみたいなことはないのでしょうか?
 よろしくお願いします。
>  こんばんは。
> 今、SQLのAテーブルからデータを読み込み、ListViewで表示、選択した行をBテーブルへ追加・・・とします。ちなみに、AとBのテーブルのレイアウトは違います。月1回の締め日まで、どんどんBテーブルに追加のみです。
>
> SQL += "insert into Bテーブル (○○区分,△△コード・・・
> で追加していますが、同じKEYレコードを追加しようとした時にエラー回避するには、同じKEYのデータがBテーブルにないかどうかあらかじめ検索するのか、または、Insertする時にダメな時は何かコードが返ってくるみたいなことはないのでしょうか?
>  よろしくお願いします。

Shinoさんこんにちは。
上記の内容ですが、実装するとすればおっしゃるとおり
Keyを先に検索して判別するか、
またはInsert時のエラーを拾うしか無いと思います。

ただ、エラーを拾うのはあまりいい方法では無いと思うので、
select count文等でKeyの重複をチェックするやり方がいいと思います。
> SQL += "insert into Bテーブル (○○区分,△△コード・・・
> で追加していますが、同じKEYレコードを追加しようとした時にエラー回避するには、同じKEYのデータがBテーブルにないかどうかあらかじめ検索するのか、または、Insertする時にダメな時は何かコードが返ってくるみたいなことはないのでしょうか?
>  よろしくお願いします。

仰る通りの方法が考えられます。
当然、先にチェックする方がパフォーマンス的にも良いでしょう。

ただ、何故に「重複データをINSERTする機会がある仕様」なのでしょうか。
多分、仕様的に良くない傾向にある気がします・・・。仕様変更不可ですか?
まあ、データ量が少なければそれほど気にはならないかと思いますが・・・。
> ただ、何故に「重複データをINSERTする機会がある仕様」なのでしょうか。
> 多分、仕様的に良くない傾向にある気がします・・・。仕様変更不可ですか?
> まあ、データ量が少なければそれほど気にはならないかと思いますが・・・。

DBにアクセスするクライアントが複数だったり、
画面でkey項目が編集できるとか、
または今後そういう拡張を考えるなら、
「重複データをINSERTする機会がある仕様」
ですので、仕様変更よりチェックを入れるべきですね。
■No5173に返信(SHさんの記事)
> DBにアクセスするクライアントが複数だったり、
> 画面でkey項目が編集できるとか、
> または今後そういう拡張を考えるなら、
> 「重複データをINSERTする機会がある仕様」
> ですので、仕様変更よりチェックを入れるべきですね。

確かにそれなら仰る通り。
INSERTだけ明記してあったので、
INSERTだけだったら別の方法で避けられるので、それが気になっただけです。

まあ履歴DBのように、INSERTだけじゃないんでしょうね。(多分)
かくゆう私も、重複する可能性のないDBでもチェック入れてるし…(当たり前?)
まあ、汎用性を利かせるためにそのチェックは親クラスで実装して、
そこを必ず通すように強制してるからなんですけど。
SHさん、Java.lang.Nullpoさん、レスありがとうございます。

 もう少し詳しく仕様を申しますと、Aテーブルの内容に、コード名称や更新日を付加したレコードを、BテーブルにInsertのみです。で、締め日後に、Bテーブルより、エクセルで○○依頼書などを一気に印刷します。
 AテーブルをListViewに表示する時は、氏名などで検索して、例えば氏名が苗字だけ入力ならば、複数表示されます。よって、たとえタナカ タロウさんのレコードをInsert後でも、タナカだけで検索すれば、タナカ タロウさんも、タナカジロウさんも表示されることになり、間違って選択して、タロウさんをInsertしようとするかもしれないからです。

>INSERTだけだったら別の方法で避けられるので・・・。

是非、教えて下さい。お願い致します。



 是非、Insertのみならば他の方法があ
o5173に返信(SHさんの記事)
>>DBにアクセスするクライアントが複数だったり、
>>画面でkey項目が編集できるとか、
>>または今後そういう拡張を考えるなら、
>>「重複データをINSERTする機会がある仕様」
>>ですので、仕様変更よりチェックを入れるべきですね。
>
> 確かにそれなら仰る通り。
> INSERTだけ明記してあったので、
> INSERTだけだったら別の方法で避けられるので、それが気になっただけです。
>
> まあ履歴DBのように、INSERTだけじゃないんでしょうね。(多分)
> かくゆう私も、重複する可能性のないDBでもチェック入れてるし…(当たり前?)
> まあ、汎用性を利かせるためにそのチェックは親クラスで実装して、
> そこを必ず通すように強制してるからなんですけど。
すいません、お願い致します。以下、消し忘れてました・・・。
>> INSERTだけだったら別の方法で避けられるので・・・。
> 是非、教えて下さい。お願い致します。

・1番楽なのは自動ナンバリング機能を使う。

・そもそも、キーを設定してレコードを一意にする意義は「重複を避けるため」です。
 重複しても良いテーブルは「重複あり」にしてあげれば問題ないです。
 (履歴DBの場合はそういうもんだと思うんですけど、今回は具合が違うのかな)

ただ、上記方法だと仕様変更が伴いますので(テーブル設計をちょいと変えるだけですが)
SHさんの言う通り、余計なことは考えないで重複チェックを行う方がプロジェクトとしては混乱しないと思われます。(次から気をつければよいことだし)
その時は重複チェックを必ず通すようなインターフェイスを実装したりすると、
グループ開発では、品質がかなり向上するでしょう。

結局、SHさんの言う通り重複チェックを入れたほうが現状は無難かと。
Shinoさん、Java.lang.Nullpoさん おはようございます。

ちょっとずれているような気もしますが、
Insertのみを考えるなら、ListViewの表示の時点で、
Bテーブルのデータの有無を検索してから表示する。
という方法もありますね。


そうすれば、ListViewに表示した時点で、
そのデータがInsert可能であるか否かわかるので、
DBへのアクセスの頻度は減ります。

それでも、Insert時のキー重複は先にチェックするほうが安心ですね。
なんにせよ、Exceptionが発生してしまうのは嫌なものですから^^;
こんにちは、Shinoさん、SHさん。

■No5200に返信(SHさんの記事)
> ちょっとずれているような気もしますが、
> Insertのみを考えるなら、ListViewの表示の時点で、
> Bテーブルのデータの有無を検索してから表示する。
> という方法もありますね。
> そうすれば、ListViewに表示した時点で、
> そのデータがInsert可能であるか否かわかるので、
> DBへのアクセスの頻度は減ります。

おお…Shinoさんの仕様詳細をちゃんと読んでいませんでした…スイマセン。
確かにその方が良さそうですね。

> それでも、Insert時のキー重複は先にチェックするほうが安心ですね。
> なんにせよ、Exceptionが発生してしまうのは嫌なものですから^^;

そもそも、例外処理って「例外時」にやるものですからね。
Exceptionクラスはインスタンス生成までに時間かかってしまいますし。
私も極力使っていません。(本当にどうしようもできない例外時だけ)

関係ない話かもしれませんが、IsDate関数も同様の理由で使ってる人いないと思います。
(というよりMicrosoft.VisualBasic名前空間の標準関数って使いたくない…)
みんな自作でやってますよね?

# スレ違いの話題でスイマセン。
みなさん、ありがとうございます。

やはり、Insert時は、先に重複チエックをするようにした方が無難みたいですね。

>Insertのみを考えるなら、ListViewの表示の時点で、
>Bテーブルのデータの有無を検索してから表示する。
>という方法もありますね。
なるほど!です。
いっそ、キー重複の時は、UPDATEにしようかな・・・と考え始めています。
と、言いますのも、Bテーブルの内容を表示する仕様の追加がありました。今の仕様は、AテーブルをListViewに表示して、いくつか内容の修正をした後(しない時もある)、Insertのみです。(でも、ListView自体には修正って出来ない?みたいですが・・・)
 後から考えてみますと、Bテーブルの内容を修正出来るようにしてほしい、と言われるのは目に見えてます。Bテーブルは表示のみに徹して、UPDATE出来ます、で逃げられないかな・・・と思っています。
■No5230に返信(Shinoさんの記事)
> やはり、Insert時は、先に重複チェックをするようにした方が無難みたいですね。

まあ、重複エラーが絶対起きないテーブルでもやってて迷惑になることもないでしょうし。
(ほとんど一瞬で終わる処理だし、仕様変更を意識しなくて良いから)

> いっそ、キー重複の時は、UPDATEにしようかな・・・と考え始めています。
> と、言いますのも、Bテーブルの内容を表示する仕様の追加がありました。今の仕様は、AテーブルをListViewに表示して、いくつか内容の修正をした後(しない時もある)、Insertのみです。

何か仕様が、しっかりと固まってないようですね。

> (でも、ListView自体には修正って出来ない?みたいですが・・・)

??どういう意味で言っているかわかりませんが、ListView自体の修正はできますよ。
DBバウンドでもできそうだし…

>  後から考えてみますと、Bテーブルの内容を修正出来るようにしてほしい、と言われるのは目に見えてます。Bテーブルは表示のみに徹して、UPDATE出来ます、で逃げられないかな・・・と思っています。

SEは大事な観点を見落として(客から要望があるのが目に見えてる機能の漏れ)
いる方も多いので、拡張し易くしとけばとりあえずよいかと。
(これは、今回に限ったことではありませんけども(^^; )

頑張ってください。
>>いっそ、キー重複の時は、UPDATEにしようかな・・・と考え始めています。
>>と、言いますのも、Bテーブルの内容を表示する仕様の追加がありました。今の仕様は、AテーブルをListViewに表示して、いくつか内容の修正をした後(しない時もある)、Insertのみです。
>
> 何か仕様が、しっかりと固まってないようですね。

出来上がったもの(途中経過でも)を見せると、
お客さんはあれもこれもしたいって言い出すことが多々ありますよね。。
全部受け入れてると終わらないので、仕様の追加・変更は、納期とかお金とか、
その辺を考えて相談したほうがいいですね ^^;

これまでの内容から勝手に想像すると、、
Aテーブルのデータをマスタとして、
それに情報を付加して、Bテーブルに入れたいようなイメージですかねぇ。

よくあるコレ系のシステムだと、
B一覧画面→Bデータ作成(編集)画面→
A(マスタ)選択→Bデータ作成画面(マスタ内容反映)

とかって流れが多いですね。
あと、Bテーブルには必ずAにある内容しか入れない。
つまり0からデータを作ることは無い。
というのであれば、Aの選択画面から入ればいいと思いますけど。。

画面のつくりにもよりますけど、
一つの画面でたくさんのことをさせようと思うと、
逆に見づらくなっちゃうことがあるので、
表示と編集の画面は分けた方がいいような気がします。

お客さんの作業の流れに沿って画面が遷移するようにすると、
お客さんが使う時にも変なことをされないで済みますし(笑)

仕様にツッコミを入れるようなマネをして申し訳ありませんです ^^;

ではでは、頑張ってください。
おはようございます。

>(でも、ListView自体には修正って出来ない?みたいですが・・・)
>
> ??どういう意味で言っているかわかりませんが、ListView自体の修正はできますよ。
> DBバウンドでもできそうだし…

このサイトのどこかで、よく似た質問を見かけました。で、ListViewのある列の内容を修正するならば、選択行を修正不可項目はLabelで、修正項目はTextBoxを表示させてそこから反映させる・・・といった感じだったので。
私がやりたいのは、ListView上で内容修正(実際は、氏名と理由名という漢字項目)です。
もし、可能ならばコード教えて頂きたいです。
よろしくお願いします。
こんにちは。

ここのサイトで探してみたら、ListviewのHeader指定ありました。そこの、ぺがらぼさんの回答を引用させて頂きます。
私は、columnsプロパティでやっていたので・・・。

with ListView1
 'カラムの追加
 .Columns.Clear() '一応、クリアしておく
 .Columns.Add("会社コード", 200, HorizontalAlignment.Left)
 .Columns.Add("会社名", 400, HorizontalAlignment.Left)
 .Columns.Add("住所", COL_WIDTH6, HorizontalAlignment.Left)
end with

どちらにしても、XPでのテストが必要ですね。
ああ、面倒だ・・・。
すいません、さっきのは、レスする場所が間違えてました。削除しようとしても・・・?すみません、無視して下さい。
■No5257に返信(Shinoさんの記事)
> このサイトのどこかで、よく似た質問を見かけました。で、ListViewのある列の内容を修正するならば、選択行を修正不可項目はLabelで、修正項目はTextBoxを表示させてそこから反映させる・・・といった感じだったので。

そんな面倒なことをやる状況ってあるのかなぁ...

> 私がやりたいのは、ListView上で内容修正(実際は、氏名と理由名という漢字項目)です。
> もし、可能ならばコード教えて頂きたいです。
> よろしくお願いします。

例えば、下記のコードだと1番若いインデックスのアイテムが編集可能になります。

ListView1.LabelEdit = True
ListView1.Items(0).BeginEdit()

これじゃ、ダメなのでしょうか?
詳細部をやりたければ、SubItem(Index)でやればできるはずです。

ListView1.Items(0).SubItems(2).BeginEdit()

あと、現在自分が触ってるインデックスの取得はツリービューもしくは、
SelectedIndex()でできるかと。

# 私も、5分前に初めてListViewを触りました。
# 今回は、意外と使えそうで嬉しいです。
> あと、現在自分が触ってるインデックスの取得はツリービューもしくは、
> SelectedIndex()でできるかと。

自分で書いてて、イミフメイでした。
TreeViewと同じ方法、もしくはSelectedItems()でできるかと。
でした。

ついでなので、

  Private Sub ltvFile_KeyDown(ByVal sender As Object, ByVal e As KeyEventArgs) Handles ltvFile.KeyDown
    If e.KeyCode = Keys.F2 Then
      ltvFile.LabelEdit = True
      ltvFile.SelectedItems(0).BeginEdit()
    End If
  End Sub

/* ltvFile が ListViewコントロールです。*/
こんばんは。

>ListView1.LabelEdit = True
>ListView1.Items(0).BeginEdit()
で先頭項目修正出来ました!
希望どおりの感じです。ありがとうございます!

ですが、
>ListView1.Items(0).SubItems(2).BeginEdit()
は、'BeginEdit' は 'System.Windows.Forms.ListViewItem.ListViewSubItem' のメンバではありません。ってエラーになります。
なぜでしょう・・・??
おはようございます。Shinoさん。

■No5295に返信(Shinoさんの記事)
> ですが、
> >ListView1.Items(0).SubItems(2).BeginEdit()
> は、'BeginEdit' は 'System.Windows.Forms.ListViewItem.ListViewSubItem' のメンバではありません。ってエラーになります。
> なぜでしょう・・・??

確かにSubItemsメンバ内にそのようなメソッドはありませんでした。
すいません、想像でモノを書いてはいけませんでしたね。(なにぶん、昨日触ったばかりでしたので…)
しかし、SubItem(詳細表示でないと意味がないですが)は変更ができないっぽいですね。
まあ、情報を載せておくところを直接変えることなど普通はないのでしょうけど。
もしやりたければ、TextBoxかなんかで代用もできるし…。
その方がわかりやすいでしょうし。

もしかして、SubItemsも変えたい仕様ですか?(^^;A
表示方法は「大きなアイコン」「小さなアイコン」「一覧」「詳細表示」
どれで、いくつもりですか?
おはようございます。java.lang.Nullpoさん。
>
>>>ListView1.Items(0).SubItems(2).BeginEdit()
>>は、'BeginEdit' は 'System.Windows.Forms.ListViewItem.ListViewSubItem' のメンバではありません。ってエラーになります。
>
> 確かにSubItemsメンバ内にそのようなメソッドはありませんでした。
> すいません、想像でモノを書いてはいけませんでしたね。(なにぶん、昨日触ったばかりでしたので…)
> しかし、SubItem(詳細表示でないと意味がないですが)は変更ができないっぽいですね。

仕様は、AテーブルをListviewで一覧表示(1行に1レコード)→ ある項目を修正(Aテーブルにはない項目なので、空白を修正)→ OKなら更新ボタン押してその行をBテーブルに追加、という感じです。

ListviewのViewプロパティはDetailsです。

SubItemは、やっぱり修正出来ないんですね・・・。
やはり、TextBoxから入力して・・・って感じですね。

ちなみに、先頭列だけ変えることって何か使い道ってあるのでしょうか・・・?
■No5301に返信(Shinoさんの記事)
> 仕様は、AテーブルをListviewで一覧表示(1行に1レコード)→ ある項目を修正(Aテーブルにはない項目なので、空白を修正)→ OKなら更新ボタン押してその行をBテーブルに追加、という感じです。
> ListviewのViewプロパティはDetailsです。
> SubItemは、やっぱり修正出来ないんですね・・・。
> やはり、TextBoxから入力して・・・って感じですね。

その場合は、

 画面上方にListViewコントロールがあって、ある行を選択すると、
 下方のTextBox群に、その情報が表示され、そのTextBoxで変更して更新。

とするべきでしょうね。(仕様が確定しているなら、どうしようもないんでしょうけど)

これなら、作りやすいしユーザも直感的にわかるでしょうね。
もし、擬似的に直接変更しているように見せたい場合は、
位置合わせが面倒だと思います。(OS依存でずれることを考えると)


> ちなみに、先頭列だけ変えることって何か使い道ってあるのでしょうか・・・?

元々、ListViewって、ファイル名を変更したりする時に使うようなイメージがありますからね。
その場合って、ファイル名は変えてもいいけどその情報は変えちゃいけないですよね?
そういう概念だと思います。

# そういう意味では、DataGridでやった方が作りやすかったのかもしれません。
みなさんこんにちわ。

ListView上でのSubItemの直接編集は出来なかったと思います。
僕も以前同様のことで悩みました・・・

どうしても一覧上で直接編集したいのなら、DataGridを使うしか無いと思います。
ただ、その場合本当に全項目編集可という状況じゃないと、
制御が結構面倒です。

で、出来上がったものも操作してみると使い勝手が良くない印象を受けました。

多分、Shinoさんがご覧になった"似たような記事"の内容も、
僕が書いたやつだと思います(^^;

操作的には面倒な気がしないでも無いですが・・・
みなさんこんばんは。大変、お世話になっております。

 最終的な仕様としては、AテーブルをListviewに一覧表示 → 選択したら、一覧の下にKEY項目などをTextBoxに表示 → 項目の修正もあればTextBoxでする → ボタン押して更新(Insert)です。
更新しようとしたデータが既にあれば、先にチエックして、更新ボタン押せません。

また、修正間違って更新した場合は、Bテーブルを一覧表示させる画面で、レコード選択すれば、削除出来るようにしました。
Bテーブル一覧画面で、修正も出来るようにすべきか迷いましたが、運用上、後から修正をたくさんすることがおかしいし、削除が出来れば、またAからBを追加する時に修正してもらえればいいかな、と。

そこで、関連してお聞きしたいのですが、Listviewで行を選択すると、最初の列(item)
だけ色が反転しますが、行全体を反転させるコードを教えて頂きたいです。
よろしくお願い致します。
2004/08/06(Fri) 11:24:16 編集(投稿者)

■No5390に返信(Shinoさんの記事)
> そこで、関連してお聞きしたいのですが、Listviewで行を選択すると、最初の列(item)
> だけ色が反転しますが、行全体を反転させるコードを教えて頂きたいです。
> よろしくお願い致します。


/* それこそ、Grid系コントロールを使った方がいいような…。*/

■修正
 すいません。早とちりしてました。
 FullRowSelectプロパティをTrueにすれば出来ました!(汗
 起動時に、「ListView1.FullRowSelect = True」 か、
 画面デザイナから、直接プロパティウィンドウでTrueにしておいて下さい。
Shinoさんこんにちわ。

>>そこで、関連してお聞きしたいのですが、Listviewで行を選択すると、最初の列(item)
>>だけ色が反転しますが、行全体を反転させるコードを教えて頂きたいです。
>>よろしくお願い致します。
>
> それこそ、Grid系コントロールを使った方がいいような…。

ListViewの、FullRowSelect プロパティをTrueにすれば出来たと思います。
java.lang.Nullpoさん、SHさん、こんにちは。

FullRowSelect プロパティをTrueにすれば、うまく行きました!
ありがとうございます!!

で、Listview選択→内容をTextBoxに表示し、
タブやマウスでカーソルを持って行くと、ListViewの選択は解除されますが、
カーソルを動かしても、選択されているように出来ないでしょうか?

今、TextChangedイベントの中で、Listview1.〜でいろいろ書いているのですが
分かりません・・・。
申し訳ないです、お願い致します。
こんにちわ。

> で、Listview選択→内容をTextBoxに表示し、
> タブやマウスでカーソルを持って行くと、ListViewの選択は解除されますが、
> カーソルを動かしても、選択されているように出来ないでしょうか?
>
> 今、TextChangedイベントの中で、Listview1.〜でいろいろ書いているのですが
> 分かりません・・・。
> 申し訳ないです、お願い致します。

コレは、HideSelectionプロパティを、Falseにすれば出来ます。
SHさん、即レスして頂き本当にありがとうございます。

HideSelectionプロパティをFalseで出来ました!!

但し、カーソルが移動すると、Listviewの選択行の色が薄くなります。
薄くならなくするのは可能でしょうか?
重ね重ね申し訳ないです。

プロパティだけで、結構制御出来るものなんですね。
もっとプロパティを見るようにします。
このコントロールなら、こんなプロパティがあるはず・・・とか
想像がつくようにしないといけないんでしょうね・・・?
Shinoさん、こんにちわ。

> 但し、カーソルが移動すると、Listviewの選択行の色が薄くなります。
> 薄くならなくするのは可能でしょうか?
> 重ね重ね申し訳ないです。

これをやるのは難しいと思いますよー^^;

もしやるとしたら、ListViewからフォーカスが外れるときに
選択行の背景色を意図的に変えるようにしないといけません。
で。今度はListViewにフォーカスが戻ってきたら、
全アイテムの背景色を戻す。っていうような処理をしないといけません。
結構面倒だと思います。

それか、普通の選択色とhideSelection時の薄くなった選択色が、
両方強調されるような色をListViewのデフォルトの背景色を変更するとか。。


> プロパティだけで、結構制御出来るものなんですね。
> もっとプロパティを見るようにします。
> このコントロールなら、こんなプロパティがあるはず・・・とか
> 想像がつくようにしないといけないんでしょうね・・・?

そうですねー^^;
というよりかは、コントロールにこういうことやらせたい!
と思ったときに、(楽して)プロパティで出来ちゃわないかなぁ・・・
って思うようにするといいと思います。

僕は、横着なのですぐプロパティを見ます。
コーディングするのは面倒ですからね(笑)
SHさん、またまた即レスありがとうございます。

どうやら、かなり面倒そうですね・・・。
ユーザーには、こういうもんです、で押してみます(笑)
でも頑張れば出来そう・・・かな?

本来の質問の件は解決していますし、今度はフロッピーから読み込み、
データ更新・・・の作り込みに入りたいと思います。
またお聞きすることがあると思いますので、またよろしくお願い致します。

ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板