- PR -

同じ主キーを持つデータの更新について

投稿者投稿内容
nsfj
会議室デビュー日: 2002/08/09
投稿数: 12
投稿日時: 2002-10-11 17:20
さて、主キーに関する論議は他スレで続けるとして、そもそもの質問にあった「主キーの更新ができない」についてです。

これはサンプルの仕様です。
このサンプルは「更新」を押すとその時の主キーテキストボックス内の値で更新対象レコードを検索に行き更新するよう、SqlCommandのUPDATE文が実行されます。
主キーを変更できるなら、取得した時点(編集する前)の値で対象レコードを検索すべきです。
で、このサンプルの場合は、この好ましくない状況を回避すべく、主キーを変更できないようグリッドのデザインを変えるという次のサンプルへ進んでいきます。

それでは主キーを変更できる場合の例を私の経験上で書きます。
実はDataGridに表示する際には、DataTableにデータを取得し、そのDefaultView(新規のDataViewでもOK)をDataGridのDataSourceに設定してます。
DataGridで更新した時に直接DB更新に行かず、一旦このDataViewに対して変更をかけ、DataAdapterのUpdateメソッドを使えば変更前の値で検索し更新してくれます。
DataGridの更新行に対応するDataViewの行はDataGridのUpdateCommandイベント内でE.Item.DataSetIndexでわかります。
但し、DataTableをセッションに保持しておかないと他からの変更によってDataSetIndexが違うレコードをさす可能性があります。
DataAdapterへのUpdateCommandの作成はあらかじめSelectCommandをセットしておいてSqlCommandBuilderを使うと楽です。

なぜこんなことができるかというとDataTable内には取得時点のデータを保持しているからです。これはオプティミスティック同時実行制御の際の対象データの取得時点との一貫性保持にも使用されます。
ash
会議室デビュー日: 2002/09/15
投稿数: 12
投稿日時: 2002-10-12 00:00
最初の質問者のashです。

主キーは、商品番号の文字列を使っています。
で、新規追加でデータを入力した後で、どうしてもその商品番号を
変更したい場合も考えて、変更できるようにしているのです。
(ちなみに、商品番号は同じデータが重複しないように、
主キーにしているのです。)
というわけで、結局その主キーのレコードのすべてチェックするしか
ないと思うんですが、その列に関係あるようなRowなどを使ってみましたが
うまく行かないのです。
主キーの全レコードのデータを調べる方法とかあるのでしょうか?
よろしくお願いします。

一番最後にレスをいただいたnsfjさんの場合だと、
同じ主キーがあっても更新できると言う事でしょうか?
初心者なので、勘違いしていたら申し訳ありません。
べーちゃん
大ベテラン
会議室デビュー日: 2002/07/21
投稿数: 121
投稿日時: 2002-10-12 05:14
>同じ主キーがあっても更新できると言う事でしょうか?

主キーというのはデータを識別するために使われる要素で、同一テーブル中に
重複が許されません。従ってテーブル中に「同じ主キーが」存在することは
絶対にありえません。登録しようとするとデータベースが登録できませんと
エラーを返してくるはずです。

>主キーは、商品番号の文字列を使っています。
>で、新規追加でデータを入力した後で、どうしてもその商品番号を
>変更したい場合も考えて、変更できるようにしているのです。
>(ちなみに、商品番号は同じデータが重複しないように、
>主キーにしているのです。)

もうひとつ言うと、主キーには原則として変化しないデータを指定するものです。

例えば次のようなケースが考えられるからです。
-他のテーブル(例えば売上テーブル)で商品の識別に商品番号を使っている場合
 元の商品テーブルの商品番号が変更されてしまうと売上テーブルとの整合が
 取れなくなってしまう。

従って、おっしゃられているケースでは大体、システムでシーケンシャルな数値を
生成して、そのデータを主キーにし、商品番号にはユニーク制約を使うのが普通です。
中には商品登録時には仮の番号を振っておき、後で正規の商品番号をあてがう
こともあるかもしれません。しかし、こうすることにより、商品番号が変化しても
主キー自体は変化しないようにできるのです。

ただ、原則的には商品番号は売上データなんかと直結していることもあり、
変化しないようにすべきではあります。それで上記以外でも同じ商品で商品番号が
変化する必要がある場合で売上データなんかがある場合は、商品番号を変更するので
なく、新規の商品登録として扱うほうが無難です。
ash
会議室デビュー日: 2002/09/15
投稿数: 12
投稿日時: 2002-10-13 02:55
ashです。

早速のレスありがとうございます。
主キーは例え、重複しないデータを入力しようが、
基本的には変更できないものであり、変更するのはよくないのですね。
べーちゃんやみなさんのアドバイスに従って、
データの更新の所は、主キーのデータを入力できないようにし、
新規の所で、追加する(もし、主キーが重複していたら、エラーメッセージが
返ってくるので、新規の場合はOKです。)というふうにします。


また、初心者なので、理解していないかもしれませんが、
http://ja.gotdotnet.com/quickstart/aspplus/
のサーバー側のデータ アクセス→SQL データベースのデータの更新→
1番目のサンプルコードの中に
Message.InnerHtml = "エラー: 同じ主キーを持つレコードが既に存在します"
が書いてあるのに、どうして更新してしまうんだろうって不思議に思っています。
べーちゃん
大ベテラン
会議室デビュー日: 2002/07/21
投稿数: 121
投稿日時: 2002-10-14 11:00
>Message.InnerHtml = "エラー: 同じ主キーを持つレコードが既に存在します"
>が書いてあるのに、どうして更新してしまうんだろうって不思議に思っています。

おっしゃられている内容が理解できません。

try-catch-finallyの構文の意味を理解されていますか。
まだならご自分で調べてみてください。

以下既に理解済みであることを前提に話しを進めると
サンプルにおいてはtry-catchが設定されており

> MyCommand.ExecuteNonQuery()

の文で新規データの挿入を実行したとき、エラーが発生するとcatch以下の文が
実行されます(この場合SQLExceptionなのでデータベース関連のエラーが発生すると
このcatchに飛んできます)。
従って、catchが実行されているということは新規挿入が失敗している、
つまりテーブルのデータは何一つ変化(更新)していません。

さて、Exp.Numberには発生したエラーの番号が格納されており、2627という数字は

>主キーというのはデータを識別するために使われる要素で、同一テーブル中に
>重複が許されません。従ってテーブル中に「同じ主キーが」存在することは
>絶対にありえません。登録しようとするとデータベースが登録できませんと
>エラーを返してくるはずです。

と説明した通り、既にテーブルに存在する主キーのデータを使って、新規にデータを
登録しようとしたため、データベースがエラーを返しているときにシステムによって
設定されるエラーの数値です。
ash
会議室デビュー日: 2002/09/15
投稿数: 12
投稿日時: 2002-10-14 16:48
ashです。

>> Message.InnerHtml = "エラー: 同じ主キーを持つレコードが既に存在します"
>> が書いてあるのに、どうして更新してしまうんだろうって不思議に思っています。

> おっしゃられている内容が理解できません。

えーと、実際に http://ja.gotdotnet.com/quickstart/aspplus/
のサーバー側のデータ アクセス→SQL データベースのデータの更新→
1番目のサンプルを試すと、同じ主キーを入力したかかわらずに
「レコードが更新されました」とメッセージが出て、実際に主キー以外の
データが更新されているのです。
しかし、上記のアドレスのSQL データベースへのデータの挿入の所は、
同じ主キーを入力すると、「同じ主キーを持つレコードが既に存在します」
とメッセージが出て、データが追加できないようになっています。


べーちゃんが指摘されたtry-catch-finallyの構文をヘルプで見ましたが、
やっぱし、本来ならばCatch内の「同じ主キーを持つレコードが既に存在します」
と出るはずなので、SQL文や他のコードを見てみます。
まりり
ぬし
会議室デビュー日: 2001/12/05
投稿数: 329
投稿日時: 2002-10-14 23:35
ashさん:
> えーと、実際に http://ja.gotdotnet.com/quickstart/aspplus/
> のサーバー側のデータ アクセス→SQL データベースのデータの更新→
> 1番目のサンプルを試すと、同じ主キーを入力したかかわらずに
> 「レコードが更新されました」とメッセージが出て、実際に主キー以外の
> データが更新されているのです。

あの、何か誤解されているように思えて仕方がないのですが、
更新(update)使用としている限りはどんな主キーを指定しようが
更新されると思いますよ?
で、主キーを変えて更新すれば、当然そこで指定された主キーを持つ
レコードが更新されます。

.NETがどうとかではなく、まずはデータベースの概略をきっちり抑えてください。
RDBにおいて主キーがどういう役割なのかをはっきり認識しましょう。
べーちゃん
大ベテラン
会議室デビュー日: 2002/07/21
投稿数: 121
投稿日時: 2002-10-15 05:38
まりりさんがいわれているようにashさんはデータベースのことを
よくわかっておられないようですね。

今ABCという名前のテーブルがあるとします。
このテーブルには数値のIDと文字のNameという2つのフィールドがあり、
IDが主キーとして設定されているとします。
さてこのテーブルの中身が以下のようになっているとします。
ID:1,Name:AAA
ID:2,Name:BBB
ID:3,Name:CCC
ID:4,Name:DDD
ID:5,Name:EEE

このテーブルにID:3(Nameはなんでもいいですが)のデータを挿入しようと
すると、エラーが発生します。
なぜなら、主キーであるID:3のデータは既に存在しているからです。
このとき前述の、「同じ主キーを持つレコードが既に存在します」 という
エラーが発生します。
このテーブルにID:6(NameはなんでもいいですがFFFとします)のデータを
挿入しようとするとちゃんと登録できます。なぜならID:6のデータは
テーブル中に存在していないからです。データベースのデータは以下のように
なるはずです。
ID:1,Name:AAA
ID:2,Name:BBB
ID:3,Name:CCC
ID:4,Name:DDD
ID:5,Name:EEE
ID:6,Name:FFF


さて、このテーブルのID:3のName:CCCをAAAに更新したいとします。
これはNameにユニークの制約などがついていなければ更新可能です。
データベースのデータは以下のようになるはずです。
ID:1,Name:AAA
ID:2,Name:BBB
ID:3,Name:AAA
ID:4,Name:DDD
ID:5,Name:EEE
ID:6,Name:FFF

さて、このテーブルのID:7のNameをGGGに更新したいとします。
これはエラーは発生しませんがデータは変化しません。なぜかわかりますか?
なぜならこのテーブルにはID:7のデータは存在しないからです。

従って挿入と更新は違うことを理解されたほうがいいと思います。
挿入:テーブルにまだ存在していないデータを追加する。
   主キーは既に存在してはいけない。既に存在する主キーを指定すると
   エラーが発生する。テーブルのデータは挿入したデータの数だけ増える。
更新:テーブルに既に存在しているデータを更新する。条件(Where)が指定
   されていればその条件に合ったデータが更新される。条件を指定しなければ
   全データが更新される。もし設定した条件に合うデータがテーブル中に
   存在しない場合、エラーは発生しないがテーブルは変化しない。
   更新は既存のデータの内容を書き換えるだけなので、テーブルのデータ数は
   変化しない。

ということを理解したほうがいいです。

スキルアップ/キャリアアップ(JOB@IT)