Access2003での顧客管理の排他制御方法とは?

このQ&Aのポイント
  • Access2003で顧客管理を行っている際に、重複チェックや排他制御の方法が知りたいです。
  • 新規登録時に顧客IDの重複チェックを行いたいですが、どのように実装すれば良いでしょうか?
  • 他のユーザーが顧客IDを使用している場合に、メッセージを表示する方法を教えてください。
回答を見る
  • ベストアンサー

Access2003での排他制御

Access2003での排他制御 顧客管理をAccess2003で行っています。 新規で登録するときに顧客IDの重複チェックを[顧客ID_LostFocus]内で DCountを使って行っています。 [cmd登録_Click]で Set db = CurrentDb Set rst = db.OpenRecordset("顧客情報") With rst .AddNew ![顧客id] = me.txt顧客ID.value ![顧客住所] = me.txt顧客住所.value ![顧客TEL] = me.txt顧客TEL.value ・ ・ ・ .Update End With 以上の処理を行っています。 (1)Aさんが新規登録で顧客IDを入力 (2)重複されていないので顧客名や住所の入力をおこなう。 (3)Bさんが同じ顧客IDで新規登録 このケースの場合、 Aさんはまだ登録処理が済んでいない(登録ボタンを押していないためテーブルに反映されていない) ので(3)ではBさんの顧客IDは重複されていません。 Aさんが入力中の顧客IDをBさんが入力した時に「他のユーザーが使用しています」みたいな メッセージを表示するにはどのようにしたらよろしいでしょうか?? 文章が上手く書けなくてもうしわけありません、 何卒宜しくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • 30246kiku
  • ベストアンサー率73% (370/504)
回答No.3

直接的な回答にならないと思います(バフッとした感じで) テーブル「T2」に、「番号」「名前」「登録日」があったとして、 長整数の「番号」を、新規登録のたびに+1していく例になります。 (エラー処理等、はしょっています) (Updateでのみエラーが発生するものとして記述しています) (番号の重複のみが引っかかる場合になります) 「番号」には重複なしのインデックスが設定されているものとします。 新規登録時、操作が競合しないように、「番号」を -999999 で一度登録します。 重複のエラーになったら時間をおいてリトライします。 登録成功で、「番号」最大値+1を覚えておいて、-999999 を書き換えます。 (登録成功で新規登録を抑止できるので、チェックをしたいのであればこのタイミングで) Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Function AddRec() As Boolean   Dim db As DAO.Database   Dim rs As DAO.Recordset   Dim iPhase As Integer   Dim sSql(1) As String   Dim iErrCnt As Integer   Dim bErrFound As Boolean   Dim iTmp As Long   Const iNumFix As Long = -999999   Const iRetryCount As Integer = 3   Set db = CurrentDb   sSql(0) = "SELECT TOP 1 * FROM T2 ORDER BY 番号 DESC;"   sSql(1) = "SELECT * FROM T2 WHERE 番号 = " & iNumFix & ";"   On Error GoTo ERR_HND   iErrCnt = 0   iPhase = 0   Do While (iErrCnt < iRetryCount)     bErrFound = False     Set rs = db.OpenRecordset(sSql(iPhase))     Select Case iPhase       Case 0         rs.AddNew         rs("番号") = iNumFix         rs("名前") = "AAAABCD"         rs("登録日") = Date         rs.Update         If (Not bErrFound) Then           rs.Requery           If (rs("番号") = iNumFix) Then             iTmp = 1           Else             iTmp = rs("番号") + 1           End If           iErrCnt = 0         End If       Case 1         rs.Edit         rs("番号") = iTmp         rs.Update     End Select     rs.Close     Set rs = Nothing     If (bErrFound) Then       Sleep 100     Else       iPhase = iPhase + 1       If (iPhase > 1) Then Exit Do     End If   Loop   Set db = Nothing   AddRec = iErrCnt < iRetryCount   Exit Function ERR_HND:   rs.CancelUpdate   iErrCnt = iErrCnt + 1   bErrFound = True   iTmp = iTmp + 1   Resume Next End Function フォームから設定値を持って来る、 登録に成功した値をフォームに戻す等は、応用の範囲と思います。 「番号」-999999 が(エラーやトラブルで)残ったままへの処理は、 別途 -999999 を削除するものを作成するとか レコードに登録した日時フィールドを追加して時間差を見て削除する処理を盛り込むとか・・・ (この場合は各PCの時刻合わせが必要と思います) 「番号」を採番する規則がなければ、この方法では?

kazuya_rx93
質問者

補足

ご丁寧な回答ありがとうございます。 顧客IDは規則性はないです。 このロジックなら上手くいきそうです! そもそも今の自分の作り方が正しいのかよくわかりません・・・。

その他の回答 (3)

  • sppla
  • ベストアンサー率51% (185/360)
回答No.4

No2です。 エラー処理ですが、AddNewの前にOn Error GoToを使用してエラー時にエラー処理ルーチンに飛ばしたらどうかということです。エラー処理ルーチン内ではErrオブジェクトを利用してエラーの種類を判別して対応するメッセージを表示するか、もしくはErr.Descriptionでエラーメッセージを表示されたらどうかということです。 これでエラーメッセージ終了後に画面に制御を戻すという感じです。 (結局、どこでチェックをしようと、チェック開始前から関連するテーブル全体をロックして他からの更新を排除して処理を行うようなことでもない限り、チェック後にAddNewが完了するまでの間に他から更新される可能性が否定できません。ですのでこのように実行時エラーに備えます。)

  • sppla
  • ベストアンサー率51% (185/360)
回答No.2

私としては仕様変更をお薦めします。 このプログラムはフォームのあるMDBとデータ(テーブル)のMDBを分離して作成し、非連結フォームで入力して更新時にテーブルに登録するタイプのプログラムではないかと想像しています。 この場合にAさん側で起動しているプログラムととBさん側で起動しているプログラムとでやりとりを行えるのはテーブルを介してしか手段がありません。 こうなりますと、Aさんが画面で入力中(まだ顧客情報テーブルには未登録)の顧客IDをBさん側で把握するためには、データのMDBに画面で入力中の顧客IDを一時保存するテーブルを作成し、Aさんが顧客IDを入力した際に(チェックが通った後に)その一時保存用テーブルに入力中の顧客IDを記録するような処理が必要になります。またこれに伴い少なくとも下記の処理が必要です。 ・顧客IDのチェックは「顧客情報」テーブル+上記の一時保存用テーブルの両方に対して行う。 ・画面で顧客IDを新しく入力した際には、一時保存用テーブルに顧客IDを登録する。 ・画面で顧客IDを修正した際には、一時保存用テーブルに登録されている顧客IDも修正する。 ・画面で更新したもしくは更新せず画面を終了した際には、一時保存用テーブルの顧客IDを削除する。 しかも、これだけやっても厳密に考えると一時保存用テーブルへの登録時に重複する可能性もありえるわけで・・・ こう考えますと、下記の仕様にした方がいいのではと思います。 ・更新時にもう一度チェックを行う。(この場合LostFocusでのチェックは不要かもしれません) ・それでもタイミングが一致してテーブル登録時に重複する可能性があるので、AddNewする際にエラー処理を行う。(重複エラー時にその旨をメッセージ表示し、修正できるように画面に制御を戻す。)

kazuya_rx93
質問者

補足

お丁寧な説明ありがとうございます。 >フォームのあるMDBとデータ(テーブル)のMDBを分離して作成し、 >非連結フォームで入力して更新時にテーブルに登録するタイプのプログラムではないかと >想像しています。 その通りです。 LostFocusでは重複チェックは行わないで更新時にチェックを行うことにしまう。 >AddNewする際にエラー処理を行う これは、 if CheckId(me.txt顧客ID.Value) = true then ←CheckId:Dcountを行っている関数 msgbox("顧客IDが重複しています") else rst.AddNew ・ ・ ・ endif ということでしょうか??

  • piroin654
  • ベストアンサー率75% (692/917)
回答No.1

たぶん以下の要件が必要になるのでしょうから、 これらの要件で検索をしてみてください。 (1) 排他制御とトランザクション処理を行なう。 (2) その時のロックの競合を回避する。 (3) ロックしたPCあるいはユーザーを確認、取得 例として http://www.accessclub.jp/bbs3/0092/superbeg33086.html

kazuya_rx93
質問者

お礼

簡単そうで複雑なロジックになりそうなので 別の方法を考えます。 また教えていただければ幸いです。 ありがとうございます。

関連するQ&A

  • yymmddを用いた管理番号のエラーについて

    以前、こちらでfuuten_no_nekoさまに大変お世話になったものです。 以前のIDがわからなくなり、再登録しました。 まえに、helpaccessのIDで質問させていただいた件について、困ったことが出てきたので、 再度、こちらでお助けいただければと思い質問させていただきました。 以前、こちらで教えていただき、Accessで、管理番号追加というボタンを作成し、そのボタンを押すと、 yymmddプラス2ケタの通し番号が自動的に払いだされるようにしておりました。 たとえば、今日が 2009年12月25日なら、09122501から順に、09122502、09122503とボタンをクリックする度に払い だされるようになっておりました。 ただ、2010年に変わったとたん、たとえば、今日が2010年1月5日なら、一度目のクリックでは、 10010501と払いだされるのですが、2度目のクリックで桁数が増え、010010502と、最初に0が ついてしまい、実行時エラー3022となります。 デバックをクリックすると、下記VBAの←部分が黄色く反転しています。 rst.Fields("管理番号").Value = MngNo rst.Fields("刃具ID").Value = 刃具ID rst.Fields("顧客ID").Value = 顧客ID rst.Fields("登録日").Value = Date rst.Update   ←←←←←←←←←←←←←<この部分が黄色く反転している> 2010年になったことが原因なのでしょうか。 恐れ入りますが、従来通り、8ケタで表示できる方法がおわかりであればどなたかどうぞ教えてくださいませ。 なにとぞ、よろしくお願い申し上げます。 管理番号追加ボタンのVBA ******************************************************************************************** Private Sub コマンド16_Click() Dim dbs As Database Dim stDocName As String Dim rst As DAO.Recordset Dim 刃具ID As Integer Dim 顧客ID As Integer Set rst = Me.Recordset If rst.RecordCount > 0 Then rst.MoveLast End If 刃具ID = Form_管理番号フォーム.刃具ID 顧客ID = Form_管理番号フォーム.顧客ID If rst.Fields("登録日").Value = Date Then MngNo = rst.Fields("管理番号").Value + 1 MngNo = "0" & MngNo Else MngNo = Format(Date, "yymmdd") & "01" End If Set dbs = CurrentDb Set rst = dbs.OpenRecordset("管理番号テーブル") rst.AddNew rst.Fields("管理番号").Value = MngNo rst.Fields("刃具ID").Value = 刃具ID rst.Fields("顧客ID").Value = 顧客ID rst.Fields("登録日").Value = Date rst.Update On Error GoTo errorhandler16 Set rst = Me.Recordset With rst .Requery .MoveLast .MovePrevious .MovePrevious .MovePrevious .MovePrevious End With errorhandler16: MsgBox "管理Noを追加しました!" & Chr(13) _ & "「顧客名」を確認のうえ、「再研磨記録フォーム」にて" & Chr(13) _ & "受付日の登録手続きをしてください。", vbOKOnly + vbInformation, "メッセージ" Me.Requery End Sub ********************************************************************************************

  • 排他制御に関して

    こんばんは。お世話になっております。 これまで、質問のタイトルにある「排他制御」というものが「同時アクセスでの不具合を避けるための・・」といった程度の知識しかないまま、DB(MySQL)を利用して会員制のサイトを作っているのですが、全体を見直すべく、いざこの排他制御というものを取り入れようとしてみたところ、手持ちの書籍やこれまで見たサイトでは、ファイルをロック・・・などと言った感じで、DBとの関わりがイメージ出来ず、会員の登録情報の変更ページなどの入力フォームをはじめ、ログインページやDBを用いた検索ページにおいての活用は、どのような手順になるのでしょうか? 些か抽象的な質問になっておりますが、取り掛かりがつかめず、例えばログインページを例にとり、IDとパスワードを入力・DBに問合せ、といった流れでは、どのような手順になるかの全体像だけでもアドバイスいただければと、投函させて頂きました。 お忙しい中恐縮ですが、アドバイスなど頂戴できれば幸いです。宜しくお願い申し上げます。

    • ベストアンサー
    • PHP
  • VBAでフォーム登録する場合の未入力のエラー

    病院を登録するフォームをつくっています。 名前を入れて登録。その後、入力画面がnullになる。 というのはできたのですが、未入力の場合 (登録した後、クリックしたときに) フィールドに必要なプロパティが True に設定されているため~~ と出てしまいます。 そのエラーメッセージを「"入力してください"」 のメッセージBOXに変えたくて上記のようにしたのですが、 変わりません。どこがおかしいのでしょうか。 どなたか、分かる方ご指導くださいませ。 Private Sub コマンド0_Click() Dim db As Database, rst As Recordset Set db = CurrentDb Set rst = db.OpenRecordset("T_病院", dbOpenTable, dbAppendOnly) With rst .AddNew ![病院名] = Me.病院名 If Me![病院名] = Null Then MsgBox "入力してください" GoTo minyuuryoku End If .Update minyuuryoku: End With Me.病院名 = Null With db End With rst.Close db.Close Set db = Nothing End Sub

  • Access2000 フォームからレコード検索

    Access2000で質問です。 「顧客テーブル」を作ります。 顧客テーブルには以下のフィールドを設けます。 顧客ID(主キー) 名前 TEL 住所 変更住所 顧客IDから住所まではすでにデータが入っています。 「変更住所」に新しくデータを入れていきます。 その際に、フォームを利用したいと思っていますが、 新規フォーム(何もデータが入っていない)に顧客IDを入れたら、すでに顧客テーブルに入力されている名前、TEL、住所がパッと表示され、変更住所だけが空欄で表示されるようなフォームを作りたいと思います。 どのような方法がありますでしょうか? ぜひお知恵を貸してください。よろしくお願いいたします。

  • VBA マクロ 修正

    Private Sub UserForm_Initialize() Me.lbl行番号.Caption = Worksheets("顧客情報").Range("A1").CurrentRegion.Rows.Count + 1 End Sub Private Sub cmd検索_Click() frm顧客検索.Show vbModal If rtnNo > 1 Then With Worksheets("顧客情報") Me.lbl行番号.Caption = rtnNo Me.txt顧客番号 = .Cells(rtnNo, 1) Me.txt顧客名 = .Cells(rtnNo, 2) Me.txt生年月日 = .Cells(rtnNo, 3) Me.txt年齢 = .Cells(rtnNo, 4) Me.txt性別 = .Cells(rtnNo, 5) Me.txt郵便番号 = .Cells(rtnNo, 6) Me.txt住所 = .Cells(rtnNo, 7) Me.txt電話番号1 = .Cells(rtnNo, 8) Me.txt電話番号2 = .Cells(rtnNo, 9) Me.txt携帯番号 = .Cells(rtnNo, 10) End With End If End Sub Private Sub cmd登録_Click() Dim wRow As Long If Me.txt顧客番号 = "" Then MsgBox "顧客番号を入力してください。", vbExclamation + vbOKOnly, "入力エラー" Exit Sub End If If Me.txt顧客名 = "" Then MsgBox "顧客名を入力してください。", vbExclamation + vbOKOnly, "入力エラー" Exit Sub End If With Worksheets("顧客情報") wRow = .Range("A" & Rows.Count).End(xlUp).Row + 1 .Cells(wRow, 1) = Me.txt顧客番号 .Cells(wRow, 2) = Me.txt顧客名 .Cells(wRow, 3) = Me.txt生年月日 .Cells(wRow, 4) = Me.txt年齢 .Cells(wRow, 5) = Me.txt性別 .Cells(wRow, 6) = Me.txt郵便番号 .Cells(wRow, 7) = Me.txt住所 .Cells(wRow, 8) = Me.txt電話番号1 .Cells(wRow, 9) = Me.txt電話番号2 .Cells(wRow, 10) = Me.txt携帯番号 End With Unload Me End Sub エクセルのマクロを設定しました。 登録時ここでエラーがでてしまうのですがなぜでしょうか? Cells(wRow, 10) = Me.txt携帯番号 Cells(wRow, 10) = Me.txt携帯番号ここの部分を消し 登録してみると登録ができるのですが・・・ わからなくなり書き込みました 宜しくお願いします

  • DB INSERT 時の排他制御について

    初めて投稿するものです。 Java で DB 挿入処理 (会員登録) で悩んでおります。 DB はPostgreSQL8です。 挿入しようとしている会員テーブルは以下のようなレイアウトです。 会員テーブル  ・会員ID 主キー  ・ログインID NOT NULL(*)  ・メールアドレス NOT NULL(*)  ・会員名  ・... ※(*)にはユニーク制約を付けています。 会員IDはPostgreSQLのシーケンスで採番するため、 排他ロックは不要であると思っております。 ですが、ログインIDとメールアドレスは ユニークであるため、排他制御して重複 チェックしなければならないと思っています。 ユニーク制約を張っているため、例外が 発生して判定するというアイデアもあるとは 思いますが、例外で重複判定するのは できれば避けたいと思っております。 例外以外で安全に重複チェックする 場合、どのように排他制御するべきでしょうか? そもそも、排他制御せずに重複チェックを 安全にする方法はあるのでしょうか? ユーザーが多いサイトの場合、テーブルを ロックすると遅くなるような気がします。 ご教授よろしくお願いいたします。

  • Access 複数テーブルをまとめる

    こんにちは! 過去記事を検索しましたが、該当がなく、苦戦しております… お知恵をお貸し下さいm(__)m テーブル T顧客…顧客ID(主キー)、名前、… T書類1…顧客ID(重複キー有)、書類1ID、… T書類2…顧客ID(重複キー有)、書類2ID、… T書類3…顧客ID(重複キー有)、書類3ID、… T書類4…顧客ID(重複キー有)、書類4ID、…  ・  ・  ・ その他に複数同じような構造のテーブルがあります。 テーブル内には他に様々なフィールドがありますが、同一内容の結合できるフィールドは上記のみです。 上記のテーブルですべての書類IDを取ってきたいのですが、 全テーブルを顧客IDと結合し、選択クエリで抽出すると      顧客ID | 名前 | 書類1ID | 書類2ID | 書類3ID | 書類4ID  1  |  Aさん |  10  |  5 |  20  |  26  1  |  Aさん |  10  |  30 |  20  |  25  1  |  Aさん |  10   |  4 |  20  |  26  1  |  Aさん |  10   |  6 |   20  |  25  2  |  Bさん |  30  |  13 |  25  |  5  2  |  Bさん |  30   |  10 |  26  |  5  2  |  Bさん |  30   |  13 |  26  |  5  2  |  Bさん |  30  |  10 |  25  |  5 のような値が出てきてしまいます…当たり前の結果ですが… やりたいこととして、 (1)一つのテーブルかクエリで抽出 顧客ID   名前   書類1ID   書類2ID   書類3ID   書類4ID  1     Aさん   |  10  |  5  |  20  |  26               |     |  30  |     |  25               |     |  4               |     |  6    2     Bさん   |  30  |  13  |  25  |  5               |     |  10  |  26   のように重複をなくし、 (2)更にまとめたものにしたいです。 顧客ID   名前   書類1ID   書類2ID   書類3ID   書類4ID  1     Aさん     10     5,30,4,6     20     25,26  2     Bさん     30      10,13     25,26     5 最終的に上記にまとまったものをフォームにして、顧客IDごとに抽出し、 顧客ごとの各書類のIDはこれとこれですよ!みたいにしたいのです! 説明が下手で申し訳ありませんm(__)m Access初心者で、独学でコツコツやっているので、知識が乏しいです… 調べてみるとユニオンクエリとかでできるような記事はありますが、 SQL文なども理解ができずに苦戦しております… お手数ですが、ご教示の程 よろしくお願い申し上げます。

  • エクセル フォーム マクロ

    Private Sub cmd登録_Click() '← 登録ボタン押下時の処理追加 Dim wRow As Long If Me.txtNo = "" Then '顧客番号が未入力の場合はエラー表示 MsgBox "顧客番号を入力してください。", vbExclamation + vbOKOnly, "入力エラー" Exit Sub End If If Me.txt氏名 = "" Then '顧客名が未入力の場合はエラー表示 MsgBox "顧客名を入力してください。", vbExclamation + vbOKOnly, "入力エラー" Exit Sub End If With Worksheets("顧客情報") wRow = .Range("A1").CurrentRegion.Rows.Count + 1 '← 最終行+1 .Cells(wRow, 1) = Me.txtNo 'フォームに入力された各データをシートに送る .Cells(wRow, 2) = Me.txt氏名 .Cells(wRow, 3) = Me.txt生年月日 .Cells(wRow, 4) = Me.txt年齢 .Cells(wRow, 5) = Me.txt性別 .Cells(wRow, 6) = Me.txt郵便番号 .Cells(wRow, 7) = Me.txt住所 .Cells(wRow, 8) = Me.txt電話番号1 .Cells(wRow, 9) = Me.txt電話番号2 .Cells(wRow, 9) = Me.txt携帯番号 End With Unload Me '← フォームを閉じる End Sub これで作成したのですがうまく動かず 助けてほしいです A1:M3までセル結合しそこにボタンをいろいろ配置しました A4にタイトル(No、氏名、生年月日・・・・・)を書きておいときました フォームを作成呼びだし打ったら タイトルのところがすべて置き換わってしまう 再度押すとA4が再度置換される 次の行に移ってくれなくなりました なぜでしょうか? wRow = .Range("A1").CurrentRegion.Rows.Count + 1 '← 最終行+1 この部分かと思いA1→A5に変更してみてもうまくいきません どうすればいいでしょうか?

  • ACCESS VBAで抽出条件の書き方

    フォームに、テキストボックス(名前「txt住所」)とコマンドボタン(名前「cmd開く」)を作成しています。 テキストボックスに入力した値と等しいレコードだけを、F_顧客フォームに表示するには以下のように書く。 とテキストに書いてありました。 Private Sub cmd開く_Click() DoCmd.OpenForm "f_顧客", , , "住所='" & Me!txt住所 & "'" End Sub ・・・質問があるのですが。 なぜMe!txt住所は、&(文字列連結演算子)で囲まないといけないのでしょうか?? そして、& Me!txt住所のあとにスペースをいれないと、構文エラーになるのですが、スペースが必要なのはなぜでしょうか??

  • Access DLookup関数で複数条件の記述

    とても困っているので、どなたか教えて下さい! 今AccessでDLookup関数を使ってフィールドの値を取り出そうとしているのですが、 色んなエラーメッセージが出て先に進めません。 ★値を取り出そうとしているテーブル★ ■顧客台帳  ・顧客ID(オートナンバ)  ・顧客氏名(テキスト型)  ・生年月日(日付・時刻型)      以下略 ここから DLookup("顧客ID", "01顧客管理台帳", "顧客氏名 = " & Chr(34) & Me.Txt顧客氏名 & Chr(34) And "生年月日 = " & Me.Txt生年月日) 補足:Me.Txt顧客氏名(書式なし)    Me.Txt生年月日(日付(S)定型入力9999/99/99)    は、事前に入力されているものとします。 という式を使って、入力した顧客氏名と生年月日に一致する顧客IDを取り出したいのですが、 「型が違います」というエラーが出てしまいます。 条件式に[ ]等をつけてみても、「指定した式で参照されている'|'フィールドが見つかりません」 という様なエラーが出てしまいます。 条件の部分が間違っていると思うのですが、この式、またはやり方の問題点がお分かりになる方がおられましたら、ご指摘の方よろしくお願いいたします。