2−6 MySQLテーブルの追加・更新をする(その2)

 処理の概要前回、 3・4の項目で データの追加・更新について書いてみましたが、既にテーブルにデータが存在する場合には更新、データが無い場合には追加を行う必要があります。コマンドを用いて処理を行う場合には 対象となるデータの有無をまず判定して その結果によって追加か更新かを判断してコマンドを作成・実行せねばなりません。コマンドを利用するのであれば DataAdapterを使わずDataReaderを使う方が良いように思います。

1.コマンドを利用して 対象のデータを追加・更新
 MySQLのテーブルに対してSelectCommandを実行してDataReaderのデータセットを作成。この件数が0件であればInsertCommandを実行してデータを追加、件数が1件以上あれば 対象キーの値をUpdateCommandによって書き換えしてやるという内容です。(どうした理由なのかは不明なのですが、一度SelectCommandにてデータを読み込んだ後は、接続を終了させてから再び接続しないとエラーになってしまいます。パフォーマンスの観点から見てどうかと思いましたが そのまま作成しています。)

Private Sub 店名更新ToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles 店名更新UToolStripMenuItem.Click
Dim sqlCont As New MySql.Data.MySqlClient.MySqlConnection 'SQL接続
Dim sqlCMDS As MySql.Data.MySqlClient.MySqlCommand 'コマンド
Dim sqlCMDU As MySql.Data.MySqlClient.MySqlCommand 'コマンド
Dim sqlCMDI As MySql.Data.MySqlClient.MySqlCommand 'コマンド
Dim sqlDr As MySql.Data.MySqlClient.MySqlDataReader 'データリーダー
Dim MyconString As String = "server=localhost;user id=hanbai;password=password;database=tanpin;"
Dim I As Long 'カウンター
'接続文字列を設定
sqlCont.ConnectionString = MyconString
Try
'MAK Select command
sqlCMDS = sqlCont.CreateCommand
sqlCMDS.CommandText = "select tencode, tenname from tentbl where tencode = ?tencode"
Dim MySParm = sqlCMDS.Parameters.AddWithValue("?tencode", MySqlDbType.Int16)
'Mak Update command
sqlCMDU = sqlCont.CreateCommand
sqlCMDU.CommandText = "UPDATE tentbl SET tenname = ?tenname " & _
"WHERE tencode = ?tencode"
sqlCMDU.Parameters.Add(New MySqlParameter("?tencode", MySqlDbType.Int16))
sqlCMDU.Parameters.Add(New MySqlParameter("?tenname", MySqlDbType.VarString))
'Mak Insert command
sqlCMDI = sqlCont.CreateCommand
sqlCMDI.CommandText = "INSERT INTO tentbl ( tencode, tenname) VALUES ( ?tencode, ?tenname)"
sqlCMDI.Parameters.Add(New MySqlParameter("?tencode", MySqlDbType.Int16))
sqlCMDI.Parameters.Add(New MySqlParameter("?tenname", MySqlDbType.VarString))
Try
'接続を作成して
sqlCont.Open()
'パラメータ値を指定して
MySParm.Value = TextBox1.Text
'検索結果を確認する。
sqlDr = sqlCMDS.ExecuteReader
I = 0
While (sqlDr.Read())
I = I + 1
End While
sqlCont.Close()
MessageBox.Show(Str(I) & "件ありました")
'
'接続を作成して
sqlCont.Open()
Select Case I
Case 0
sqlCMDI.Parameters("?tencode").Value = TextBox1.Text
sqlCMDI.Parameters("?tenname").Value = TextBox2.Text
'内容を追加します。
sqlCMDI.ExecuteNonQuery()
Case Else
sqlCMDU.Parameters("?tencode").Value = TextBox1.Text
sqlCMDU.Parameters("?tenname").Value = TextBox2.Text
'内容を更新します。
sqlCMDU.ExecuteNonQuery()
End Select
Catch ex As MySqlException
MessageBox.Show(ex.Message)
Finally
sqlCont.Close()
End Try
Catch ex As MySqlException
MessageBox.Show(ex.Message)
Finally
End Try
End Sub

2.DataAdapterを利用して 対象のデータを追加・更新
DataAdapter利用例 同じ結果が得られるのですが、今度はDataAdapterを用いてテーブルからDatasetを作成。この内容に対して追加・更新を行った後に 元のテーブルへ内容を反映させるコマンドを自動作成させ テーブルを更新する例を見てみましょう。
 この場合も考え方は同じで 作成されたDataSetの件数を確認し 件数が0件ならば追加、件数があれば更新するというものです。この場合は、1の場合と違ってコマンドを作成する必要性も 接続・切断を明示的に書く必要も無いので比較的簡便に使えます。

Private Sub データ取得後AToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles 全件取得後AToolStripMenuItem.Click
Dim sqlDA As MySql.Data.MySqlClient.MySqlDataAdapter 'データアダプタ作成
Dim sqlCmdBldr As MySqlCommandBuilder 'SQLコマンド作成
Dim resultDS As DataSet 'データセットオブジェクト
Dim oDR As DataRow 'データオブジェクト
Dim MyconString As String 'MySQL接続文字列
Dim I As Integer 'カウンター
'DataAdapterオブジェクトの作成
sqlDA = New MySql.Data.MySqlClient.MySqlDataAdapter
'DataSetオブジェクトの作成
resultDS = New DataSet()
'MySQL接続文字列
MyconString = "server=localhost;user id=hanbai;password=password;database=tanpin;"
Try
'接続を作成します
sqlDA.SelectCommand = New MySqlCommand()
sqlDA.SelectCommand.CommandType = CommandType.Text
sqlDA.SelectCommand.CommandText = "select * from tentbl where tencode = ?tencode"
Dim MyParm = sqlDA.SelectCommand.Parameters.AddWithValue("?tencode", MySqlDbType.Int16)
sqlDA.SelectCommand.Connection = New MySqlConnection(MyconString)
'データ読み込みし 更新
Try
'パラメータ値を指定して
MyParm.Value = TextBox1.Text
'検索結果を確認する。
sqlDA.Fill(resultDS, "tentbl")
'Dataset内のテーブル"tentbl"の件数を確認
I = resultDS.Tables("tentbl").Rows.Count
Select Case I
Case 0
oDR = resultDS.Tables("tentbl").NewRow()
oDR.BeginEdit()
oDR("tencode") = TextBox1.Text
oDR("tenname") = TextBox2.Text
oDR.EndEdit()
resultDS.Tables("tentbl").Rows.Add(oDR)
Case Else
'テーブル"tentbl"の先頭値に対する更新処理
resultDS.Tables("tentbl").Rows(0).Item("tenname") = TextBox2.Text
End Select
Try
'Update文の自動実行のためにCommandBuilderオブジェクトを作成する
sqlCmdBldr = New MySqlCommandBuilder(sqlDA)
'DataSetに対する更新結果をDBに反映
sqlDA.Update(resultDS, "tentbl")
MessageBox.Show("レコードは更新されました")
Catch ex As MySqlException
MessageBox.Show(ex.Message)
End Try
Catch ex As MySqlException
MessageBox.Show(ex.Message)
End Try
Catch ex As MySqlException
MessageBox.Show(ex.Message)
End Try
End Sub

 簡単に説明すると、sqlDAというDataAdapterを作成し、店コードをパラメータとして持つresultDSというDataSetを 店コードを指定して作成します。このDataSetの件数を確認して、対象のキーをもつデータが無ければ oDRという新しいDataRowを作成して、ここに値を入れてDataSetを更新します。データがある場合には単純に1件目のデータを書き換えしています。
 この後、sqlCmdBldrという名称のコマンドを自動作成させ、Updateコマンドによって 元のデータベースを更新するわけです。DataSetを正しく更新出来れば、元テーブルにたいする変更が追加であっても 更新であってもその部分は.NET側が行ってくれます。

3.DataAdapterをもっとうまく利用できないか?
 DataSetに加えた変更は Updateによって元のデータベースに戻されるようです。従って、テーブルの全てのデータを一旦Datasetに取り込みしてから 最終的に戻すようにすれば何度もキー値がデータベースにあるかどうかを確認しなくてもよさそうです。しかし、この考えはうまくいきませんでした。内容としては
1.作成されるDataSetにはキーが無いので Filterコマンドによって 値の検索が出来なかった。
2.キーを作る為には Tableを作成するようになるが、うまく作成できなかった。(この部分は今後も調査します)
3.全てのデータを読み込む場合に データ量が多いとパフォーマンスが悪くなるかも?
等です。

 それならば、適当なキーをセットして空のDataSetを自動作成させ、この内容にデータを追加してゆき(元のデータベースのデータ有無に関わりなく)最後に コマンドを作成させて 内容を反映させたら良いのではないか?と考え、実行してみたところ、該当キーが無い場合にはうまく追加されたのですが(当然ですが) キーが存在すると「Duplicate entry '25' for key 1」というエラーメッセージが出てしまいました。これは、店番号25番を(既にテーブルに存在するにも関わらず)追加しようとした為で、やはりきちんと存在確認しながらデータ処理をする必要がありそうです。

プログラムの内容を上のように書くと、インデントされていない為に読みづらくなってしまいます。この為、内容をPDF化したものをつけてあります。必要ならこちらを参照してみて下さい。PDFファイル。ちなみに、このファイルはVisualBasic 2005 Expressの内容をOpenOffice.Org2.4のWriterに貼り付けし PDFにエクスポートしたものです。テキストコピー可の形で作成していますので、そのまま使用することも可能です。

「市民の目」トップページへ戻る