- 締切済み
アクセス:フォームを閉じずにデータ更新するには
みなさん、おはようございます。 データベースアクセスについて質問させていただきます。参考書やこちらの質問等もしらべましたが回答が得られなかったので質問致します。 現在、アクセスで病院のベッドを管理するアプリを開発中です。 ひとつのフォームに全病棟のベッドを表示するため500以上のコントロールを配置しておりますが、 すべて非連結にして、フォームを開くときのイベントプロシージャーにクエリを開いてすべてコントロールにテーブルのデータをはめていくように設計しています。 で、問題はこのフォームを開いたまま最新のデータに更新させたいのですが、再クエリーではうまくいきませんでした。 なぜうまくいかないのか理由はわかっていません(プログラマーの方ならうまくいかなくて当然とおっしゃるかもしれませんが) で、仕方なく、一定間隔の時間ごとにフォームを閉じて開くという方法を取っています。 この方法では遅いマシンだと再表示に時間がかかるのできっとほかにスマートなよい方法があるとおもっているのですがプログラミングのスキルが乏しいため詰まっております。 お知恵をお借りできれば幸いです。
- みんなの回答 (11)
- 専門家の回答
みんなの回答
平面的に表示し、定期的に情報を更新するフリーのアプリケーションを見つけました。 http://awplus.jp/soft/page1/aj/bedmng.html プロトタイプということなので、実用にはならないでしょうが、ソースコードが公開されているために、参考にはなりそうです。オブジェクトを配列で管理しています。言語はデルファイみたいですが。
>>おぼろげに、配列を使えばきっとシンプルにできるんだろうな~と感じていましたが. . . . 配列とオブジェクト指向を組み合わせるのに、好適なケースかもしれません 1.エディットから派生させたクラスに、データベースとのI/Oなどを追加する 2.エディットの替わりにパネルなどから派生させれば、複数の情報を、テキストボックスだけではなく、ラジオボタン、チェックボックス、コンボボックスなどを使って多彩な表示ができる 3.オブジェクト(病床)にフォーカスがあるとき、当該レコードとつながるようにすれば、マルチユーザーによるデータの矛盾もデータベースが面倒をみてくれる 4.表示位置情報などはデータベースで管理すれば、フォーム上への配置は動的に行え、それ以後の管理は配列でできる 5.病床の増減もプログラムをいじらずにデータだけで処理できる 6.改修工事などによる一時的病床の使用不可も、フラッグなどで簡単に処理できる 7.コードは基本的な部分は数十行ですむ(?) 興味深いです。プロトタイプを作ってみたくなった。 しかし、VBAではほとんど不可能だと思います。一般的にはC++とかC#、ジャバあたりですかね?
- lv4u
- ベストアンサー率27% (1862/6715)
>>おぼろげに、配列を使えばきっとシンプルにできるんだろうな~と感じていましたが、まったくスキルがなくどうすればいいのかわからないのでコードが大きくなることを承知で簡単なコードをベッドごとに書きました。 その配列を使った共通ルーチンを最初に作った人は、オフコン画面の操作性を実現しようという発想でした。でも、簡単にはできあがらず、その会社(当時いた会社)の社長は、売上が無いため「こりゃ首をくくるしかないか?」と枝ぶりのいい木を探したそうです。だから、ちょっと考えて、できそうに思えても、完成するまでの道は長いですね。 それから、私もVBの書籍をたまに見ることありますが、同様なロジックで作ったものは見たことありません(探す範囲が狭いかも?)。ちなみに、似たような考え方のルーチンは、アメリカのデータベースソフトの画面入力関数(C言語)で目にしたことはあります。でも、膨大な関数群で構成されていて、またポインタのてんこ盛り状態で、これは、「天才の仕事だ。絶対自分には作れない!」と思い知らされたもんでした。
全部のベッドを見せなくても、 退院、手術、検査等の監視の必要があるベッドだけ表示させ、 変更がかかったら再表示させたらどうでしょうか? 今日、明日、明後日、一週間以内などを色別に表示させるのも良いでしょう。
- lv4u
- ベストアンサー率27% (1862/6715)
補足です。 >>「500以上のコントロール」などというのもすごい力業だし。 私の場合は、コントロールを配列で操作し、基本的な処理を共通ルーチン化して処理していましたね。 ですので、コントロールが3つでも、500でも、その部分のコード増大はありませんでした。でも、フィールドによってチェック内容が増えるなどは当然あるので、コントロール数に応じて、コードは大きくなりました。
- lv4u
- ベストアンサー率27% (1862/6715)
回答への批判は禁止されていますが、私も同様に思ったことがあるので、補足として回答します。 No.5さんが >>120床を一度に見せる必要があるのかが疑問です。 と疑問をもたれていますが、私も介護のシステムを検討していたとき「なんで一度に見せないといけないの?」と思ったことがありました。 でも運用シーンでは、別の仕事をしていて手が離せず、TVを見るように、何の操作もしないで1画面だけに全ての情報を盛り込んで表示させておき、近くを通ったとき、「ちらっと見る」という使い方をすることもあるとのことで、納得しました。 No.4さんが >>そもそも非連結にしているためにいろいろ問題が発生すると考えます。 と問いかけられています。私も初めてちょっと凝ったマルチユーザでの利用を想定したアプリをアクセスで作成したとき、「非連結にするんだよ」と先輩に指導され「コードが増えるのに・・・」と思ったものです。でも、ちょっと凝った処理では、そうしないとプログラムの作成は不可能でした。もちろん、その影響でコーディング量はいやというほど増えましたね。「これって、ほとんどVisualBasicで作っているパッケージのルーチンからコピっているじゃあないですか?」って状態でした。
120床を一度に見せる必要があるのかが疑問です。 メインフォームの詳細セクションにリスト表示させ、ここに入力用のボタンを置き、 これをクリックすると別フォームで入力用フォームが表示されるようにし、 入力完了後「登録」ボタンを押すとテーブルを更新するようにすれば如何でしょう。
そもそも非連結にしているためにいろいろ問題が発生すると考えます。マルチユーザーでの表示で整合性を取ろうと苦労されているようですが、表示はうまくいっても、複数ユーザーがデータを書き換えたときの不整合にはどのように対応されるのでしょうか?通常ここら辺はデータベースがそれなりに処理してくれる部分ですが、非連結となれば、設計者が処理しなければならない。 「500以上のコントロール」などというのもすごい力業だし。 このようなハードルがあっても、なお非連結にしなければならない理由は何でしょう? これを明らかにされると別のアドバイスもあるかと考えます。
お礼
500以上になる理由は、120床あるベッド情報を一度に表示する必要があるためです。 患者氏名、退院予定日等1ベッドあたり4項目の情報を表示します。 また、トップの要望で分りやすいインタフェースでベッド情報の並びが不規則にならざるおえず、単純に帳票フォームを使えないからです。 非連結にするのは、1ユーザがテーブルを開いてデータを握ったままにしておきたくなかったからです。 追加、更新、削除はすべてクエリーで行います。 整合性については、ベッドごとにフラグ用フィールドを設けて、フラグを立てたユーザ以外はデータの参照しかできないようにする予定です。 このシステムは一日に10名も動かない入退院情報を管理するので、競合の発生率はきわめて低いと考えております。 以上が私なりの設計構想ですが忌憚ないアドバイスを頂ければ幸いです。
- lv4u
- ベストアンサー率27% (1862/6715)
>>フォームを開いたときに記述した内容のコードをそっくりタイマーイベントに記述すればいよいとおもったのですが、そうすると修正する場合、2箇所も変更する必要があるので、汎用モジュール化して、それをフォームを開くときとタイマーイベントに設定すればよいと思いましたがいかがでしょうか? 汎用モジュール化でもいいのですが、そこまでしなくとも、普通のプロシージャを作成して、フォームオープン時とタイマーイベント時の両方のイベントから呼び出すようにすれば、コードの2重化は防げると思います。イベント共用がうまくいかない場合は、それぞれの小さなイベントプロシージャから、画面設定のプロシージャを呼び出すという手もありますね。 >>おっしゃるとおり、アクセスでの運用は正直怖いのですが、そこまで病院全体がシステムを使いこなせるようになったら、本格的にオーダリングや電子カルテを導入するようになると思います。いつのことやらですが。 開発の分量を考えてみると、病院のベテラン担当者が協力会社のSEやPGさんを使いまくっても、ちょっと難しいと思いますよ。日本を代表する巨大なメーカでさえ、納品したシステムがトラブルをおこして、大病院のカルテシステムが停止し、薬が出せない状態になったこともありますしね。別のところでは、システムの保守担当が、トラブル対応が激務なため、どんどん辞めていったとか、ダウンして、その病院にお世話になった話など聞きます。(しかも、システムがまともに動作しないわけだから、徹夜などで頑張っても医師や看護師からは冷たい目で見られる) 政府は、全国共通な電子カルテシステムを作る構想があるようですから、それを待ったほうがいい気もします。ただ、丸投げ体質、ゼネコン体質の日本のIT業界で、まともなシステムが作れるか?すごく疑問なんですけどね。
非連結フォームは、多少、専用の関数を用意しないと開発が面倒です。 DisplayRecord() UpdateRecord() DeleteRecord() などです。 これらの関数一発で、フォームへの表示、書き込みも可能です。 また、抽出すべき主キーを配列変数にすれば、レコード移動ボタンの全ても自作することが可能です。 もちろん、サブフォームまで非連結にすると大変ですので主フォーム程度がお勧めです。 Private Sub Form_Load() Dim StopNow As Boolean StopNow = Not DisplayRecord(Me, "SELECT * FROM id管理表 WHERE id_name='Test'") If Not StopNow Then Message "フォームが正常に表示されました。" End If End Sub StopNow = Not UpdateRecord(Me, "SELECT * FROM id管理表 WHERE id_name='Test'") UpdateRecord関数は、いわゆる非連結フォームに入力されたデータをデータベースに書き込む関数です。書き込む表の列とフォームに配置したコントロールとの対応関係は、DisplayRecord関数と同じようにコントロールの名前で判断します。 ? DeleteRecord("SELECT * FROM id管理表") True まあ、一介のデザイナーに過ぎない素人が考えた関数です。 が、多分、非連結フォームで開発するのに必要なアイデアが含まれています。 なお、その他に、採番テーブルを管理する関数が必要なのは言うまでもありません。 Private Sub 仕入先名_BeforeUpdate(Cancel AS Integer) Dim strShiiresaki AS String Dim strWhere AS String strShiiresaki = Nz(Me.仕入先名, "") strWhere = "仕入先名='" & strShiiresaki & "' AND id<>" & Me.ID Cancel = CBool(DBLookup("id", "仕入先", strWhere, 0) <> 0) If Cancel Then Message "[仕入先名]が重複しています。" & chr$(13) & chr$(13) & _ "・{Esc}{Esc} で入力を取り消すことができます。" ElseIf isNewRecord And Me.ID = 0 Then Me.ID = NewID("仕入先_id") SetFieldEnabled Me, True End IF End Sub ' ----------------------------------------------------------------------------------------- ' フォームに読み込んだ列情報を表示します。 ' ' 【要件】 ファームのフィールド名が、<"field_" + 列名>であること。 ' ----------------------------------------------------------------------------------------- Public Function DisplayRecord(ByVal frm As Form, _ ByVal strQuerySQL As String) As Boolean On Error GoTo Err_DisplayRecord Dim isOK As Boolean Dim I As Integer Dim N As Integer Dim rst As ADODB.Recordset Dim fld As ADODB.Field isOK = True Set rst = New ADODB.Recordset rst.Open strQuerySQL, _ CurrentProject.Connection, _ adOpenStatic, _ adLockReadOnly If Not rst.BOF Then ' ================= ' Begin With: frm ' ----------------- With frm N = .Controls.Count - 1 For Each fld In rst.Fields For I = 0 To N If Mid$(.Controls(I).Name, 7) = fld.Name Then .Controls(I).Value = fld.Value Exit For End If Next I Next fld End With ' --------------- ' End With: frm ' =============== Else MsgBox " フォームに表示する情報はありません。(DisplayRecord)", vbInformation, " お知らせ" End If Exit_DisplayRecord: On Error Resume Next rst.Close Set rst = Nothing DisplayRecord = isOK Exit Function Err_DisplayRecord: isOK = False MsgBox "実行時エラーが発生しました。(DisplayRecord)" & Chr$(13) & Chr$(13) & _ "・Err.Description=" & Err.Description & Chr$(13) & _ "・SQL Text=" & strQuerySQL, _ vbExclamation, " 関数エラーメッセージ" Resume Exit_DisplayRecord End Function Public Function UpdateRecord(ByVal frm As Form, _ ByVal strSQL As String, _ Optional Echo As Boolean = False) As Boolean On Error GoTo Err_UpdateRecord Dim isOK As Boolean Dim I As Integer Dim N As Integer Dim fldName As String Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim fld As ADODB.Field isOK = True Set cnn = CurrentProject.Connection ' ================= ' Begin With: cnn ' ----------------- With cnn .Errors.Clear .BeginTrans Set rst = New ADODB.Recordset rst.Open strSQL, _ cnn, _ adOpenStatic, _ adLockOptimistic ' ================= ' Begin With: rst ' ----------------- With rst If Not .BOF Then N = frm.Controls.Count - 1 For Each fld In .Fields For I = 0 To N fldName = frm.Controls(I).Name If Left$(fldName, 6) = "field_" Then If Mid$(fldName, 7) = fld.Name Then fld.Value = frm.Controls(I).Value Exit For End If End If Next I Next fld .Update End If End With ' --------------- ' End With: rst ' =============== .CommitTrans End With ' --------------- ' End With: cnn ' =============== If Echo Then MsgBox " 1件のレコードを更新または保存しました。", vbInformation, " お知らせ" End If Exit_UpdateRecord: On Error Resume Next rst.Close Set rst = Nothing UpdateRecord = isOK Exit Function Err_UpdateRecord: isOK = False If cnn.Errors.Count > 0 Then ErrMessage cnn.Errors(0), strSQL cnn.RollbackTrans Else MsgBox "プログラムエラーが発生しました。(UpdateRecord)" & Chr$(13) & Chr$(13) & _ "・Err.Description=" & Err.Description & Chr$(13) & _ "・SQL Text=" & strSQL, _ vbExclamation, " 関数エラーメッセージ" End If Resume Exit_UpdateRecord End Function Public Function DeleteRecord(ByVal strSQL As String, _ Optional ByVal Echo As Boolean = True, _ Optional ByVal LockType As Integer = adLockPessimistic) _ As Boolean On Error Goto Err_DeleteRecord Dim isOK As Boolean Dim N As Integer Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset isOK = True Set cnn = CurrentProject.Connection ' ================= ' Begin With: cnn ' ----------------- With cnn .Errors.Clear .BeginTrans ' ---------------- ' Recordset Open ' ---------------- Set rst = New ADODB.Recordset ' ================= ' Begin with: rst ' ----------------- With rst .Open strSQL, _ cnn, _ adOpenStatic, _ LockType If Not .BOF Then .MoveFirst Do Until .EOF N = N + 1 .Delete .MoveNext Loop End If End With ' --------------- ' End With: rst ' =============== If Echo Then MsgBox N & " 件のレコードを削除しました。", vbInformation, " お知らせ" End If .CommitTrans End With ' --------------- ' End With: cnn ' =============== Exit_DeleteRecord: On Error Resume Next rst.Close ← rst、cnn は、関数から抜け出すと自動的に閉じられ破棄されます。 cnn.Close よって、これらのコードは省いても支障のないものです。 Set rst = Nothing Set cnn = Nothing DeleteRecord = isOK Exit Function Err_DeleteRecord: isOK = False If cnn.Errors.Count > 0 Then ErrMessage cnn.Errors(0), strSQL cnn.Rollbacktrans Else MsgBox "プログラムエラーが発生しました。" & _ "システム管理者に報告して下さい。(DeleteRecord)", _ vbExclamation, " 関数エラーメッセージ" End If Resume Exit_DeleteRecord
お礼
>>s_huskyさん 回答ありがとうございます。 このコードの山は厳しいですね^^; マクロ主体で自動化している私には正直???です。 ごめんなさい。 シンプルな方法があると思っていたものですから。 こういうやり方もあるっていうことは参考にさせていただきます。
- 1
- 2
お礼
おぼろげに、配列を使えばきっとシンプルにできるんだろうな~と感じていましたが、まったくスキルがなくどうすればいいのかわからないのでコードが大きくなることを承知で簡単なコードをベッドごとに書きました。ベッドのコントロールの修正が発生すると多大な労力になるのは辛いですが・・・ 配列の勉強してみようと思います。 lv4uさんのお話と同じで、当院でも一画面で直感的に空きベッドを把握したいのと、転室処理の場合にもすべてのベッドが表示されていなければ、いちいちが画面操作が必要では面倒この上ないのです。 現場はできるだけ操作がないに越したことはないですから。 余談ですが、ちなみにこの病棟画面は40インチモニタに表示します。