----------------------------------------------------------------------- Imports System.Data.SqlClient ' -------------------------------------------------- ' 顧客情報の構造体 ' -------------------------------------------------- Structure strucMemberInfo Dim strDate As String Dim strName As String Dim strZip As String Dim strAddr1 As String Dim strAddr2 As String Dim strPhone As String End Structure ' -------------------------------------------------- ' 売上伝票1件分の構造体 ' -------------------------------------------------- Structure strucSlipData Dim strItemName As String Dim intItemValue As Integer Dim intNumItems As Integer Dim lngTotalValue As Long End Structure       : (システムが自動生成したコードは省略)       : ' 顧客情報と伝票情報 Dim Customer As strucMemberInfo Dim SlipData As strucSlipData ' 伝票番号 Dim strSlipNumber As String ' -------------------------------------------------- ' フォーム上の各コントロールを初期化 ' -------------------------------------------------- Private Sub InitForm() txtDate.Text = Format("yy/mm/dd", CStr(Today)) lblGndTotal.Text = "0" ClearCustomerData() ClearSlipData() End Sub ' -------------------------------------------------- ' 顧客情報(コントロールと構造体)を初期化 ' -------------------------------------------------- Private Sub ClearCustomerData() txtCstmId.Text = "" lblCstmName.Text = "" lblCstmZip.Text = "" lblCstmAddr1.Text = "" lblCstmAddr2.Text = "" lblCstmPhone.Text = "" With Customer .strDate = "" .strName = "" .strZip = "" .strAddr1 = "" .strAddr2 = "" .strPhone = "" End With strSlipNumber = "00000000" lblSlipNumber.Text = strSlipNumber End Sub ' -------------------------------------------------- ' 伝票情報(コントロールと構造体)を初期化 ' -------------------------------------------------- Private Sub ClearSlipData() txtItemId.Text = "" txtNumItems.Text = "0" lblItemName.Text = "" lblItemValue.Text = "0" lblTotalValue.Text = "0" With SlipData .strItemName = "" .intItemValue = 0 .intNumItems = 0 .lngTotalValue = 0 End With End Sub ' -------------------------------------------------- ' 処理の取り消し ' -------------------------------------------------- Private Sub btnCancel_Click _ (ByVal sender As System.Object, ByVal e As System.EventArgs) InitForm() UpdateGrid() End Sub ' -------------------------------------------------- ' フォームの初期化 ' -------------------------------------------------- Private Sub Form1_Load _ (ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load InitForm() UpdateGrid() End Sub ' -------------------------------------------------- ' 「売上ヘッダ」のレコード件数を取得 ' 戻り値--0以上:レコード件数/-1:DBエラー ' -------------------------------------------------- Private Function GetSlipCount() As Integer Dim objConnect As New SqlConnection Dim objCommand As New SqlCommand Dim objDataReader As SqlDataReader Dim strSql As String ' 「売上ヘッダ」のレコード件数を取得 strSql = "SELECT COUNT(*) FROM 売上ヘッダ" Try ' 接続文字列の設定 objConnect.ConnectionString = _ "Persist Security Info=False;Integrated Security=SSPI;database=db1001ya;server=localhost" ' コネクションの設定 objCommand.Connection = objConnect ' 接続を開く objConnect.Open() ' SQLの設定 objCommand.CommandText = strSql objDataReader = objCommand.ExecuteReader() objDataReader.Read() ' レコード件数を戻り値に設定 GetSlipCount = objDataReader.GetInt32(0) If GetSlipCount < 0 Then GetSlipCount = 0 End If Catch objExcept As Exception ' 例外処理 MsgBox(objExcept.ToString, MsgBoxStyle.OKOnly, "DBエラー") GetSlipCount = -1 Finally ' 接続を閉じる If Not objConnect Is Nothing Then objConnect.Close() End If End Try End Function ' -------------------------------------------------- ' お客様IDが入力されたら顧客情報を表示 ' -------------------------------------------------- Private Sub txtCstmId_LostFocus _ (ByVal sender As Object, ByVal e As System.EventArgs) _ Handles txtCstmId.LostFocus Dim strSql As String Dim intSlipCount As Integer intSlipCount = GetSlipCount() ' 伝票番号が生成できなければメッセージを表示し、フォーカスを戻す If intSlipCount = -1 Then MessageBox.Show("データベースエラーのため伝票番号を生成できませんでした。" & _ vbCrLf & _ "お客様番号の入力からやり直してください。", _ "伝票番号エラー", _ MessageBoxButtons.OK, MessageBoxIcon.Error) txtCstmId.Select() Exit Sub End If ' 伝票番号(日付+連番)を生成してグローバル変数に保存 strSlipNumber = _ Format(CDate(txtDate.Text), "MMdd") & _ Format(intSlipCount + 1, "000#") lblSlipNumber.Text = strSlipNumber ' 検索用の接続文字列を設定 strSql = _ "SELECT 氏名, 郵便番号, 住所1, 住所2, 電話 FROM 得意先_mr " & _ "WHERE お客様ID = " ' テキストボックスの未入力チェック If Me.txtCstmId.Text = "" Then MessageBox.Show("お客様IDを入力してください。", _ "入力エラー", MessageBoxButtons.OK, MessageBoxIcon.Error) Else ' パラメータを付け足して検索を実行 strSql = strSql & txtCstmId.Text SearchCustomer(strSql) ' 実際の検索と表示処理 ' この時点で「売上ヘッダ」にレコードを書き込む AddHeader() End If End Sub ' -------------------------------------------------- ' 「顧客_mr」から顧客情報を検索して表示 ' -------------------------------------------------- Private Sub SearchCustomer(ByVal strSql As String) Dim objConnect As New SqlConnection Dim objCommand As New SqlCommand Dim objDataReader As SqlDataReader Try ' 接続文字列の設定 objConnect.ConnectionString = _ "Persist Security Info=False;Integrated Security=SSPI;database=db1001ya;server=localhost" ' コネクションの設定 objCommand.Connection = objConnect ' 接続を開く objConnect.Open() ' SQLの設定 objCommand.CommandText = strSql ' 検索処理(結果をデータリーダに受け取る) ' 取得するレコードは常に1件なので、パラメータにCommandBehavior.SingleRowを指定 objDataReader = objCommand.ExecuteReader(CommandBehavior.SingleRow) ' フィールドにNull値(DBNull)が入っていたら空文字列("")に置換する If objDataReader.Read() Then ' 検索成功 If Not IsDBNull(objDataReader("氏名")) Then lblCstmName.Text = objDataReader("氏名") Else lblCstmName.Text = "" End If If Not IsDBNull(objDataReader("郵便番号")) Then lblCstmZip.Text = objDataReader("郵便番号") Else lblCstmZip.Text = "" End If If Not IsDBNull(objDataReader("住所1")) Then lblCstmAddr1.Text = objDataReader("住所1") Else lblCstmAddr1.Text = "" End If If Not IsDBNull(objDataReader("住所2")) Then lblCstmAddr2.Text = objDataReader("住所2") Else lblCstmAddr2.Text = "" End If If Not IsDBNull(objDataReader("電話")) Then lblCstmPhone.Text = objDataReader("電話") Else lblCstmPhone.Text = "" End If ' 値を構造体にも保存しておく With Customer .strDate = txtDate.Text .strName = lblCstmName.Text .strZip = lblCstmZip.Text .strAddr1 = lblCstmAddr1.Text .strAddr2 = lblCstmAddr2.Text .strPhone = lblCstmPhone.Text End With Else ' 検索失敗 MessageBox.Show( _ "該当するお客様情報が見つかりません。", _ "検索エラー", _ MessageBoxButtons.OK, MessageBoxIcon.Error) InitForm() txtCstmId.Text = "" txtCstmId.Select() Exit Sub End If Catch objExcept As Exception ' 例外処理 MessageBox.Show(objExcept.ToString, "DBエラー", MessageBoxButtons.OK) Finally ' データリーダを閉じる If Not objDataReader Is Nothing Then objDataReader.Close() End If ' 接続を閉じる If Not objConnect Is Nothing Then objConnect.Close() End If End Try End Sub ' -------------------------------------------------- ' 「売上ヘッダ」に伝票の基本情報を1件追加 ' 戻り値--成功:True/失敗:False ' ※ 現時点では戻り値を使用していない ' -------------------------------------------------- Private Function AddHeader() As Boolean Dim objConnect As New SqlConnection Dim objCommand As New SqlCommand Dim strSql As String ' 追加用のSQL strSql = _ "INSERT INTO 売上ヘッダ " & _ "(伝票番号, 伝票日付, お客様ID, 伝票発行) " & _ "VALUES(" & _ strSlipNumber & ", '" & _ Customer.strDate & "', " & _ txtCstmId.Text & ", " & "0)" Try ' 接続文字列の設定 objConnect.ConnectionString = _ "Persist Security Info=False;Integrated Security=SSPI;database=db1001ya;server=localhost" ' コネクションの設定 objCommand.Connection = objConnect ' 接続を開く objConnect.Open() ' SQLの設定 objCommand.CommandText = strSql ' レコードを追加 If objCommand.ExecuteNonQuery >= 1 Then AddHeader = True Else ' 追加失敗 AddHeader = False Exit Function End If Catch objExcept As Exception ' 例外処理 MsgBox(objExcept.ToString, MsgBoxStyle.OKOnly, "DBエラー") Finally ' 接続を閉じる If Not objConnect Is Nothing Then objConnect.Close() End If End Try End Function ' -------------------------------------------------- ' 「売上明細」に1件分の売上情報を追加 ' 戻り値--成功:True/失敗:False ' ※ 現時点では戻り値を使用していない ' -------------------------------------------------- Private Function AddDetail() As Boolean Dim objConnect As New SqlConnection Dim objCommand As New SqlCommand Dim strSql As String ' 追加用のSQL strSql = _ "INSERT INTO 売上明細 " & _ "(伝票番号, 商品ID, 数量, 単価, 金額) " & _ "VALUES(" & _ strSlipNumber & ", " & _ txtItemId.Text & ", " & _ SlipData.intNumItems & ", " & _ SlipData.intItemValue & ", " & _ SlipData.lngTotalValue & _ ")" Try ' 接続文字列の設定 objConnect.ConnectionString = _ "Persist Security Info=False;Integrated Security=SSPI;database=db1001ya;server=localhost" ' コネクションの設定 objCommand.Connection = objConnect ' 接続を開く objConnect.Open() ' SQLの設定 objCommand.CommandText = strSql ' レコードを追加 If objCommand.ExecuteNonQuery >= 1 Then AddDetail = True Else ' 追加失敗 AddDetail = False End If Catch objExcept As Exception ' 例外処理 MsgBox(objExcept.ToString, MsgBoxStyle.OKOnly, "DBエラー") Finally ' 接続を閉じる If Not objConnect Is Nothing Then objConnect.Close() End If End Try End Function ' -------------------------------------------------- ' 商品IDが入力されたら商品情報を表示 ' -------------------------------------------------- Private Sub txtItemId_LostFocus _ (ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles txtItemId.LostFocus Dim strSql As String ' 検索用のSQL strSql = _ "SELECT 品名, 販売単価 FROM 商品_mr " & _ "WHERE 商品ID = " ' テキストボックスの未入力チェック If Me.txtCstmId.Text = "" Then MessageBox.Show("商品IDを入力してください。", _ "入力エラー", MessageBoxButtons.OK) Else ' パラメータを付け足して検索を実行 strSql = strSql & txtItemId.Text SearchItem(strSql) ' 実際の検索処理 End If End Sub ' -------------------------------------------------- ' 「商品_mr」から商品情報を検索して表示 ' -------------------------------------------------- Private Sub SearchItem(ByVal strSql As String) Dim objConnect As New SqlConnection Dim objCommand As New SqlCommand Dim objDataReader As SqlDataReader Try ' 接続文字列の設定 objConnect.ConnectionString = _ "Persist Security Info=False;Integrated Security=SSPI;database=db1001ya;server=localhost" ' コネクションの設定 objCommand.Connection = objConnect ' 接続を開く objConnect.Open() ' SQLの設定 objCommand.CommandText = strSql ' 検索処理(結果をデータリーダに受け取る) ' 取得するレコードは常に1件なので、パラメータにCommandBehavior.SingleRowを指定 objDataReader = objCommand.ExecuteReader(CommandBehavior.SingleRow) If objDataReader.Read() Then ' 検索成功 ' ここでもDBNull対策 If Not IsDBNull(objDataReader("品名")) Then lblItemName.Text = objDataReader("品名") Else lblItemName.Text = "" End If If Not IsDBNull(objDataReader("販売単価")) Then lblItemValue.Text = Format(objDataReader("販売単価"), "#,##0") Else lblItemValue.Text = "" End If SlipData.strItemName = lblItemName.Text SlipData.intItemValue = CInt(lblItemValue.Text) Else ' 検索失敗 MessageBox.Show( _ "該当する商品が見つかりません。", _ "検索エラー", _ MessageBoxButtons.OK, MessageBoxIcon.Error) InitForm() txtItemId.Text = "" txtItemId.Select() Exit Sub End If Catch objExcept As Exception ' 例外処理 MessageBox.Show(objExcept.ToString, "DBエラー", MessageBoxButtons.OK) Finally ' データリーダを閉じる If Not objDataReader Is Nothing Then objDataReader.Close() End If ' 接続を閉じる If Not objConnect Is Nothing Then objConnect.Close() End If End Try End Sub ' -------------------------------------------------- ' 数量が入力されたら金額を計算して表示 ' -------------------------------------------------- Private Sub txtNumItems_LostFocus _ (ByVal sender As Object, ByVal e As System.EventArgs) _ Handles txtNumItems.LostFocus Dim lngTotalValue As Long ' ただの掛け算 lngTotalValue = CLng(txtNumItems.Text) * CLng(lblItemValue.Text) ' ラベルには書式化して表示 lblTotalValue.Text = Format(lngTotalValue, "#,##0") SlipData.intNumItems = CInt(txtNumItems.Text) SlipData.lngTotalValue = lngTotalValue End Sub ' -------------------------------------------------- ' 1件分の入力を終えたらレコードを追加しグリッドを更新 ' -------------------------------------------------- Private Sub btnAdd_Click _ (ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnAdd.Click ' テーブルに1件分の売上明細を追加 AddDetail() ' グリッドを更新 UpdateGrid() ' 販売情報を初期化 ClearSlipData() End Sub ' -------------------------------------------------- ' DataGridに売上明細を表示 ' -------------------------------------------------- Private Sub UpdateGrid() Dim objSqlAdpt As SqlDataAdapter Dim dsSlipData As New DataSet Dim strSql As String ' 「売上明細」から処理中の伝票番号のレコードだけを抽出するSQL strSql = "SELECT 売上明細.商品ID, 商品_mr.品名, " & _ "売上明細.数量, 売上明細.単価, 売上明細.金額 " & _ "FROM 商品_mr INNER JOIN 売上明細 ON 商品_mr.商品ID = 売上明細.商品ID " & _ "WHERE 売上明細.伝票番号 = " & strSlipNumber Try objSqlAdpt = New SqlDataAdapter(strSql, _ "Persist Security Info=False;Integrated Security=SSPI;database=db1001ya;server=localhost") objSqlAdpt.Fill(dsSlipData, "SlipData") ' グリッドにデータセットを連結 grdSlipData.SetDataBinding(dsSlipData, "SlipData") ' グリッドのキャプションを表示 grdSlipData.CaptionText = Customer.strName & "様の売上明細" ' 総合計金額を表示 DispTotal() Catch objExcept As Exception ' 例外処理 MsgBox(objExcept.ToString, MsgBoxStyle.OKOnly, "DBエラー") Finally ' 接続を閉じる objSqlAdpt.Dispose() End Try End Sub ' -------------------------------------------------- ' 売上の総合計金額を表示 ' -------------------------------------------------- Private Sub DispTotal() Dim objConnect As New SqlConnection Dim objCommand As New SqlCommand Dim objDataReader As SqlDataReader Dim strSql As String ' 集計用SQL strSql = "SELECT SUM(金額) AS 総合計 " & _ "FROM 売上明細 WHERE 伝票番号 = " & _ strSlipNumber Try ' 接続文字列の設定 objConnect.ConnectionString = _ "Persist Security Info=False;Integrated Security=SSPI;database=db1001ya;server=localhost" ' コネクションの設定 objCommand.Connection = objConnect ' 接続を開く objConnect.Open() ' SQLの設定 objCommand.CommandText = strSql ' 集計を実行 objDataReader = objCommand.ExecuteReader() If objDataReader.Read() Then If Not IsDBNull(objDataReader("総合計")) Then lblGndTotal.Text = Format(objDataReader("総合計"), "#,##0") Else ' 失敗時には0とする lblGndTotal.Text = "0" End If End If Catch objExcept As Exception ' 例外処理 MsgBox(objExcept.ToString, MsgBoxStyle.OKOnly, "DBエラー") Finally ' 接続を閉じる If Not objConnect Is Nothing Then objConnect.Close() End If End Try End Sub ' -------------------------------------------------- ' 次の顧客のためにすべてを初期化 ' -------------------------------------------------- Private Sub btnNextCstm_Click _ (ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnNextCstm.Click InitForm() UpdateGrid() End Sub ' -------------------------------------------------- ' 処理の終了 ' -------------------------------------------------- Private Sub btnClose_Click _ (ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnClose.Click Me.Close() End Sub End Class -----------------------------------------------------------------------