VB.NETからAccessデータベースのレコードを削除する

VB.NETからAccessデータベースのレコードを削除する

DataGridView に読み込んだ、Accessのデータベースをいじっていきます! 今回はレコードの削除についてです。


関連記事

  1. DataGridViewへAccessのデータベースファイルを読み込む
  2. AccessDBテーブルの主キー情報を取得する
  3. DataGridViewに読み込んだDB情報を再取得する
  4. DataGridViewをセル編集したときの行数を格納する
  5. Accessのデータベースファイルへ書き込むための接続・切断
  6. Accessデータベースのレコードを削除する ←NOW!
  7. Accessデータベースを更新する

ガッツリ続き物になってしまいました…。過去の分と合わせて順番に読んでいただけると分かりやすいかと思います。

なるべく簡素に書いているので、例外処理は甘いと思われます。ご参考にする際は、ご自分の環境に合わせてご修正ください。

解説のためツギハギしちゃったので、最後の記事(7回め)に全コードまとめてあります。

書いたときの環境

  • Visual Studio 2010
  • .NET Framework 4.0

です。

コード

150305-1

図のようにどこかが選択されているとして、その行を削除します。

Form2.vb

前回のButton3のクリックイベントを拡張します。

'### Form2.vb ###
Public Class Form2
	'略

	'----------------------------------------------------
	'    メソッド
	'----------------------------------------------------
	'略

	'----------------------------------------------------
	'  Formイベント
	'----------------------------------------------------
	'略

	'----------------------------------------------------
	'  Buttonクリックイベント
	'----------------------------------------------------
	Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
		'再読込ボタン(Button1)クリック時(略)
	End Sub

	Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
		'保存ボタン(Button2)クリック時(略)
	End Sub

	Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
		'削除ボタン(Button3)クリック時

		'未保存データ確認
		If list.hasUpdateList = True Or list.hasInsertList = True Then
			MessageBox.Show("編集中のデータがあります。先に「保存」か「再読込」を行なってください。")
			Exit Sub
		End If

		'どこも選択されていない場合
		If dgv.CurrentCellAddress.X = -1 Then
			MessageBox.Show("削除したい行を選択してください。", "確認", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
			Exit Sub
		End If

		'削除前確認
		DataGridView1.CurrentRow.Selected = True '対象行をすべて選択
		If MessageBox.Show("選択されている行のデータを削除します。よろしいですか?", "確認", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) <> 1 Then
			Exit Sub
		End If

		'DELETEのSQL文リストを取得
		Dim sqlList As New List(Of String)
		sqlList = db.getDeleteSql(dgv.CurrentRow.Index)

		'SQLを実行()
		If db.runSQL(sqlList) = True Then '成功したら
			'再読込
			db.Dispose()
			Call setTable()
			'メッセージ
			MessageBox.Show("削除しました。")
		End If
	End Sub

	'----------------------------------------------------
	'  DataGridViewイベント
	'----------------------------------------------------
	'略
End Class

編集中のデータがあったり、どこも選択されていなかったりなど例外処理をしてから、確認メッセージを出して処理に入ります。

49行目、getDeleteSqlを呼び出して DELETE 文を生成します。前回、複数処理を踏まえて型を List にしたので、DELETE 文も List 型になるように作ります。

2018/5/31追記:新規行が選択されていた場合

コメント欄でご指摘いただいて、新規行(最後の*行)を選択してるときに「削除」ボタンを押すと、1つ前の行(データが入っている最終行)がにフォーカスが移ってしまうのに気がつきました。IsNewRow 関数使えないのかなと思ったのですがどうにも False になってしまう…、なぜだ…。。と、検証していろいろ調べてみたところ、こちらのサイトで原因と解決方法を知ることができました。

どうやら DataGridView のデフォルトの仕様として、今回のような場合はフォーカスはそのまま、カレントは新規行-1の位置に戻ってしまうらしいんですね。このおかげで IsNewRow 関数も False になってしまうという…。

それで上記サイトに記載されていたとおり、DataGridView の CausesValidation プロパティを True にしたら、IsNewRow が True で取得することができました!

というわけで、その設定にしてから、上記コードの 35 ~ 39 行目のチェック条件に以下のように付け足すことで、新規行が選択されていたときも検出して中断することができます。

'どこも選択されていない場合
If dgv.CurrentCellAddress.X = -1 Or dgv.CurrentRow.IsNewRow Then
	MessageBox.Show("削除したい行を選択してください。", "確認", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
	Exit Sub
End If

追記はここまでです。お試しください。

DBtable.vb

DELETE 文を生成するために、いろいろ関数を書いていきます。

'### DBtable.vb ###
Imports System.Data.OleDb

Class DBtable
	'略

	'----------------------------------------------------
	'  テーブルに関すること
	'----------------------------------------------------
	'略

	'----------------------------------------------------
	'  SQL文生成に関すること
	'----------------------------------------------------
	Public Function getDeleteSql(ByVal targetRow As Integer) As List(Of String)
		'DELETE文生成
		Dim list As New List(Of String)
		Dim strSQL As String

		'DELETE句
		strSQL = "DELETE FROM " & tableName
		'WHERE句
		strSQL &= getWhereTxt(targetRow) 'WHERE句を足す

		list.Add(strSQL) 'リストに追加

		Return list
	End Function

	Private Function getWhereTxt(ByVal targetRow As Integer) As String
		'WHERE句生成
		Dim encloseTxt As String
		Dim whereTxt As String = ""

		For Each clm In primaryKeyArray '主キーの列をループ
			If clm.Ordinal = 0 Then
				whereTxt = " WHERE "
			Else '主キーがふたつ以上ある場合
				whereTxt &= " AND "
			End If
			Dim TypeName As String = tableData.Columns(clm.Ordinal).DataType.Name '主キーの型タイプ
			encloseTxt = getEncloseTxt(TypeName) '囲み文字を取得
			whereTxt &= dgv.Columns(clm.Ordinal).HeaderCell.Value & "=" & encloseTxt & dgv.Rows(targetRow).Cells(clm.Ordinal).Value & encloseTxt
		Next

		Return whereTxt
	End Function

	Private Function getEncloseTxt(ByVal TypeName As String) As String
		'囲み文字の判定
		Dim encloseTxt As String
		Select Case TypeName
			Case "String"
				encloseTxt = "'"
			Case "DateTime"
				encloseTxt = "#"
			Case Else
				encloseTxt = ""
		End Select
		Return encloseTxt
	End Function
End Class

15行目、getDeleteSqlという関数で DELETE 文を List 型に入れて返します。SQL の WHERE 句を生成する処理は、他でも使えるのでそこも関数にして23行目で呼び出しています。

30行目が、WHERE 句を生成して取得するgetWhereTxt関数です。主キーとなるフィールドの数だけ組み立てます。このとき、型によって囲み文字(文字列なら「’」とか)が違うので、そこを判定する関数も別に作って42行目で呼び出しています。

49行目が、囲み文字を取得するgetEncloseTxt関数です。と言っても文字列型と日付型しか処理してませんが…。例外が出てきたらここに追記かなー。

動作確認

ここまでコードを書いてから動かしてみます。

150305-1

ひとつ選んで削除ボタンを押し、

150305-2

確認メッセージをOKしてみると、

150305-3

レコードが削除され、DataGridView が再読込されました。

以上です! 次回、UPDATE と INSERT を実装してひととおり終わりにするつもりですー!

公開日:2015/03/05
更新日:2018/05/31

書籍を執筆しています。

2件のコメント

  1. y.y より:

    データ保存後に、最終行の※のセルを選択して、削除ボタンをクリックすると
    ※の1つ前のデータが削除として選択されます。
    DataGridView1.CurrentRow.Selected = Trueの箇所で、選択行を判断してい
    箇所に何か条件を追加する必要があるようです。

    • *you より:

      y.yさん細かく検証していただいてありがとうございます。ホントですね! 対処方法を本文に追記しましたのでご参照ください。


y.y へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)