Private Sub Form_Error(DataErr As Integer, Response As Integer)
If DataErr = 3314 Then
Response = acDataErrContinue '既定のエラーメッセージを表示しない
MsgBox "入力必須なので空欄にはできません"
Me.ActiveControl.Undo
SendKeys "{TAB}" '次のコントロールへ移動
End If
End Sub
SELECT テーブル名.*
FROM テーブル名
WHERE
([都道府県]=[Forms]![Form名]![cmb1] Or [Forms]![Form名]![cmb1] Is Null)
And ([性別]=[Forms]![Form名]![cmb2] Or [Forms]![Form名]![cmb2] Is Null)
And ([既婚/未婚]=[Forms]![Form名]![cmb3] Or [Forms]![Form名]![cmb3] Is Null);
マルチユーザーアクセスを前提としているのであれば、少なくとも
SQL Server のテーブルに格納されている全てのレコードを、 編集目的のためにまるごと呼び出して表示するような処理は
極力避けた方がよいでしょう。
(トランザクションや排他ロックなどの制御を行なう必要があるなら
なおのこと)
Option Compare Database
Option Explicit
Private adoCn As ADODB.Connection
Private adoRs As ADODB.Recordset
Private Const ServerName As String = "ServerName"
Private Const UserName As String = "UserName"
Private Const Password As String = "PassWord"
Private Const CatalogName As String = "DatabaseName"
Private Const TableName As String = "TableName"
'フォームの[開く時]イベント
Private Sub Form_Open(Cancel As Integer)
On Error GoTo Err_Form_Open
Me.Painting = False
Set adoCn = New ADODB.Connection
With adoCn
'SQL Server Native Client をプロバイダーとする場合
.ConnectionString = "Provider=SQLNCLI11;" & _
"Data Source=" & ServerName & ";" & _
"User Id=" & UserName & ";" & _
"Password=" & Password & ";" & _
"Initial Catalog=" & CatalogName & ";" & _
"DataTypeCompatibility=80"
.CursorLocation = adUseClient
.CommandTimeout = 1
.Open
End With
Dim strSQL As String
strSQL = "SELECT * FROM [dbo].[" & TableName & "] ORDER BY [ID];"
Set adoRs = New ADODB.Recordset
With adoRs
Set .ActiveConnection = adoCn
.Source = strSQL
.CursorLocation = adUseClient
.CursorType = adOpenKeyset
.LockType = adLockOptimistic
.Open
End With
Set Me.Recordset = adoRs
Exit_Form_Open:
Me.Painting = True
Exit Sub
Err_Form_Open:
Dim ErrText As String
ErrText = "実行時エラー " & Err.Number & ": " & Err.Description
Debug.Print ErrText
MsgBox ErrText, vbCritical, Me.Name & ".Form_Open"
Call ReleaseObjects
Cancel = True
End Sub
'フォームの[読み込み解除時]イベント
Private Sub Form_Unload(Cancel As Integer)
Call ReleaseObjects
End Sub
'コマンドボタン[cmdExecFilter]の[クリック時]イベント
Private Sub cmdExecFilter_Click()
'編集中のカレントレコードを保存する
If Me.Dirty = True Then
DoCmd.RunCommand acCmdSaveRecord
End If
Dim strCriteria As String
'非連結テキストボックス[txtFilter]の値が
'数値データに変換可能である場合
If IsNumeric(Me![txtFilter].Value) Then
'フィールド[ID]の値が、非連結テキストボックス[txtFilter]の値を
'整数値に変換した結果と等しいレコードを抽出する条件式
strCriteria = "[ID]=" & CLng(Me![txtFilter].Value)
End If
'フィルターを適用
adoRs.Filter = strCriteria
'レコードセットを再連結
Me.Painting = False
Set Me.Recordset = Nothing
Set Me.Recordset = adoRs
Me.Painting = True
End Sub
'コマンドボタン[cmdClose]の[クリック時]イベント
Private Sub cmdClose_Click()
'このフォームを閉じる
DoCmd.Close acForm, Me.Name, acSaveNo
End Sub
'オブジェクトの解放処理
Private Sub ReleaseObjects()
On Error Resume Next
If Not adoRs Is Nothing Then
If adoRs.State = adStateOpen Then
adoRs.Close
End If
Set adoRs = Nothing
End If
If Not adoCn Is Nothing Then
If adoCn.State = adStateOpen Then
adoCn.Close
End If
Set adoCn = Nothing
End If
End Sub
Private Sub Form_Current()
With Me.Parent.Form
!cmb_分類 = Me!分類
!txb_コード = Me!コード
!txb_品名 = Me!品名
!cmb_単位 = Me!単位
!txb_巾 = Me!巾
!txb_長さ = Me!長さ
!txb_登録日 = Me!登録日
!txb_更新日 = Me!更新日
!txb_単価 = Me!単価
!txb_改訂前単価 = Me!改訂前単価
End With
End Sub
次にメインフォームの各コマンドボタンのクリック時のイベントプロシージャを下記のように記述します。
Private Sub 修正_Click()
With Me.F_売上.Form
!分類 = Me!cmb_分類
!コード = Me!txb_コード
!品名 = Me!txb_品名
!単位 = Me!cmb_単位
!巾 = Me!txb_巾
!長さ = Me!txb_長さ
!登録日 = Me!txb_登録日
!更新日 = Me!txb_更新日
!単価 = Me!txb_単価
!改訂前単価 = Me!txb_改訂前単価
.Refresh 'レコードソースのテーブルに反映
End With
End Sub
Private Sub 削除_Click()
With Me.F_売上.Form
'サブフォームが新規レコードでなければ、カレントレコードを削除
If Not .NewRecord Then .Recordset.Delete
End With
End Sub
1.から3.までは挙動を確認できています
4.については、フォーカスがText1から動いていないので、動作していないように見受けられますが、処理が停止しているわけではないようです。
試しに全ての行間および最終行にMsgBoxを挿入してみましたが、すべて表示されます。
「値がフィールドまたは……」のメッセージが表示されるのは、全ての処理が完了した後のようです。
既定のエラーメッセージの抑制はできているということですね。
私のコードの動作想定は、
ですが、どれが実行されてないですか。
エラーコード3314にあたる、「フィールドに値を入力してください。」という1つ目のメッセージは抑止できているようです。
はい。フォームプロパティの「エラー時」を[イベント プロシージャ]に変更し、ビルドボタンをクリックしてコードを記述しましたので。
フォームのデザインビューで、フォームプロパティの「エラー時」が
[イベント プロシージャ]
となってますか。また、そこのビルドボタンをクリックすると、前回の回答のコードが表示されますか。
早速のご回答、ありがとうございます。
私が記述したBeforeUpdate部をコメント化し、教えていただいたForm.Errorの記述を追加しましたが、それでも「値がフィールドまたはレコードの入力規則に違反しています。」のエラーが出てしまいました。
入力必須違反エラーは、フォームのエラー時イベントで拾えます。
Form.Error イベント (Access) | Microsoft Docs
hiroton様、hatena様
どうもありがとうございます。
解決いたしました。
主キーでも「規定値」プロパティが設定されているとNullでない場合もあります。
もし、その場合は、
NewRecordプロパティを参照すれば新規レコードかどうか判定できます。
新規レコードなら主キーがnullなので
みたいな形で
テキスト型のフィールドならば、
テーブルのデザインビューで、フィールドのプロパティを下記のように設定すると、
未入力は Null ではなく ""(空文字列)になります。
値要求 はい
空文字列の許可 はい
入力済みのフィールドは変わらないので、更新クエリか、置換で
Nullを""に更新します。
これで、質問の式か、下記の式でOKになります。
Like Nz([Forms]![Form名]![cmb1], '*')
ご提案ありがとうございます。
ちょっと、うまくいきませんでした。
この部分は、Nullにならないように、入力時にチェック機能をつけて、対応したいと思います
ありがとうございました。
前回の回答だと、インデックスが無効になるので、データ数が多いと重くなる場合があります。その場合は、下記のようにしてください。
SQLビューで下記のように記述します。
テーブル名、フィールド名は実際のものに変更してください。
保存するときは、SQLビューのまま保存してください。デザインビューにすると、複雑に書き換えられてしまうので、デザインビューにして保存しないようにしてください。
下記のようにフィールド欄に式を設定して、抽出条件をTrueにしたらどうでしょう。
IIf([Forms]![Form名]![cmb1] is null , True, [forms]![form名]![cmb1]=[フィールド名])
他のフィールドも同様に設定してください。
ご回答ありがとうございます。
ご指摘の件、確認して理解いたしました。
データにNull値がないようにするセーフティーネットはつけていなかったので、
Nullのデータがある場合には検索ができなくなりますね。
対処法はあるのでしょうか。
like iif([forms]![form名]![cmb1] is null , '*', [forms]![form名]![cmb1])
これだと、Null値のレコードは抽出されません。
テーブルに Nullのレコードがなければいいですが。
Office VBA Reference: Bind a form to an ADO Recordset
・そのレコードセットが ADO を介して更新可能であること。
・そのレコードセットに一意なインデックス(テーブルの主キーなど)が含まれていること。
基本的には上記の条件を満たしているか否か次第。
なので、レコードセットを開く際にどのような SQL 文を実行しているかも
無関係ではありません。
ADO.Recordset オブジェクトと連結されたフォームにおいて、
そのフォームの Recordset プロパティを介して Filter プロパティを
設定するのは無効です。
そのテーブルやフォームの使用目的によるとしか。
マルチユーザーアクセスを前提としているのであれば、少なくとも
SQL Server のテーブルに格納されている全てのレコードを、
編集目的のためにまるごと呼び出して表示するような処理は
極力避けた方がよいでしょう。
(トランザクションや排他ロックなどの制御を行なう必要があるなら
なおのこと)
とりあえずの例としては、上記のようなコードが挙げられますが。
自己解決したみたいです。
系を使えばよいのですね。
なかなか、回答が付かないですね。
私自身は、SQL Serverでの経験がないので、適切な回答はできないので、
感想的な回答ですので、参考程度に。
そのようなソースのリンクがあれば紹介してもらえますか。
個人的には、リンクテーブルだから遅いのではなく、リンクテーブルと連結したフォームだと、常に更新可能なレコードセットとしてサーバーデータと常時接続された状態だから、遅いのだと思います。
ですので、ADOのレコードセットを開いて、フォームと連結させたら、結局、上記と同じ状態なので、速度的にはたいしてかわらないと推測しています。
もし、リンクテーブルと連結したフォームより、ADOのレコードセットと連結したフォームの方が速度的に有利であるという信頼できるソースがあるなら知りたいです。
下記によると要件さえ満たしいれば、更新可能になるようです。
ADO レコードセットにフォームを連結します | Microsoft Docs
フォームのそのようなプロパティはレコードソースで接続していることが前提のようで、Recordsetプロパティで連結した場合はほとんど使えないようです。RecordsetのFilterプロパティを使うか、SQLでレコードセットを再取得して、それと連結させるという処理が必要なようです。
ということで、あくまで、想像ですが、
連結フォームのような使い勝手は難しいと思います。
結局、速度改善したいなら、
パススルークエリで、必要なデータのみ取得して、これは閲覧のみ、更新する場合は、別に非連結フォームで更新したものを、更新クエリ、あるいは追加クエリでデータ更新することになるのではと思っています。
いつも教えていただいてありがとうございます。勉強させていただいています。
見積書を作るにあたって、材料マスタのデータを抽出して使いたいのですが、色々変更などを言われていて
レイアウトなどが変わりそうなので、また改めて質問させてください。
引き続き勉強していきます。
またよろしくお願いします。
hatena 様
お世話になります。
2つ目にお教えいただいたようにいたしましたら、うまくいきました。
ありがとうございました。
今後ともよろしくお願いいたします。
現状の1列表示のレポートを修正するなら、
レポートをデザインビューで開いて、[ページ設定]の[レイアウト]で、列数を3に設定してサイズをラベルのサイズに設定してください。
[作成]-[レポート]-[宛名ラベル]をクリックして「宛名ラベルウィザード」でご使用の用紙の品番を探してみてください。
あれば、そのままウィザードを進めていけばできます。
なければ、ラベルサイズが近いものを選択するか、[ユーザー定義ラベル]でラベルサイズや余白、列数を自由に設定できます。
一つのフォームの中でデータを書き込む場合、たとえば
と記述します。
Me
は自分自身を表すキーワードなので、異なるフォームを相手にする場合はこれを書き換えてあげますMe
フォームを直接指定する記述Forms!フォーム名
としてあげればいいですこれとは別に、データ構造の問題もあると思うので、必要であれば情報を追記してください
たとえば、
・見積に材料マスタのデータを結び付ける必要がある場合
・参考データとして既存のデータを呼び出したいだけの場合
やりたいことによってデータ構造(と、制御処理)が変わってきます
わざわざ調べていただき、ありがとうございます。
やっぱりエラーがでるので、フォームをコピーしてから開いてみたらエラーが出ませんでした。
理由はわかりませんが、ありがとうございました。
登録ボタンと修正ボタンの方も、教えていただいたコードを使ってできるようになりました。
ありがとうございます。また一歩前に進みました。
やりたいことはあって、書籍やYoutubeやネットを色々みて勉強しているつもりなのですが、
知識が追い付かないので、なかなか思うようにできません…
お聞きしてばかりで本当に申し訳ないです。
また教えてください。よろしくお願いします。
当方のサンプルで確認してみましたが、
でエラーがでることはないですね。
ファイルの破損が疑われますので、修復・最適化をしてみるか、下記で紹介しているリフレッシュを試してみてください。
AccessのDBファイルを長期的に安定して使用するには - hatena chips
下記で紹介している方法が使えると思います。
レコード入力時に「保存」コマンドボタンでのみレコード保存できるようにする - hatena chips
いつも大変お世話になっています。教えていただきありがとうございました。
分割フォームは、作ってみたのですがうまくいかなくて、今回のような形で作ってみました。
でも、スキルが必要とのことだったので、こちらはいつかちゃんとできるようになってから再度チャレンジするとして、
もう一度分割フォームで作成してみました。
それで、一応形はできたと思うのですが、少し質問させてください。
1.フォームをポップアップにして、開いた時のサイズを指定したいのですが、この分割フォームで作ったものを
他のものと同じように設定したところ、下記のようなエラーがでてしまいます。
コードは、「開く時」のところに
Private Sub Form_Open(Cancel As Integer)
DoCmd.SelectObject acForm, Me.Name
DoCmd.MoveSize , , 13000, 9200
End Sub
と入れていました。エラーが出るので、指定せずに開くと画面いっぱいになってしまって、使いづらいです…
2.登録する時と修正する時に、登録ボタンと修正ボタンを押さないとできないようにすることはできますか。
(これができないような気がして、サブフォームで非連結のフォームを作ってみました)
いつも教えていただいて申し訳ありません。
よろしくお願いします。
推測ですが、Windowsの「カスタムスケーリング」の設定がPCによって異なっているのではないでしょうか。
「カスタムスケーリング」の設定を同じにしてみてください。
【Windows10】画面の解像度を変えずに文字だけを拡大する方法 - 特選街web
まず、回答の前にひとつ提案ですが、
現状のサブフォームのレコードソースのテーブルから、分割フォームを作成すれば、単票フォームの下にデータシートビューが表示されて、データシートでレコードを選択して、単票フォームの方でそのレコードの編集ができるようになります。
いっさいVBAなしで、見た目は現状とほぼ同じものが作成できます。
分割フォーム(単票フォームとデータシートを同時に表示)の作成と使い方 | Access 2016 | 初心者のためのOffice講座
上記を検討されることをお勧めします。
現状のサブフォーム形式で行く場合、かなりのスキルを必要とします。
本題
サブフォーム形式にチャレンジするということなら、
まずは、サブフォームのレコード移動時のイベントプロシージャを下記のように記述します。
次にメインフォームの各コマンドボタンのクリック時のイベントプロシージャを下記のように記述します。
このような設計にした場合、
現状の登録ボタンとクリアボタンの処理は再検討する必要があると思います。
登録ボタンは、サブフォームが新規レコードのときのみ有効にするとか。
また、クリアボタンが必要かどうかも検討する必要があります。
あともう一点お聞きさせてください。
先ほど、自分のパソコン(デスクトップPC)とは違うパソコン(ノートPC)で作ったデータを見せてもらったら、
レイアウトが少しずれていました。(線が重なっていたり離れていたり、文字の位置がずれていたり)
自分のパソコンからはきれいに見えていたのでちょっとショックだったのですが、
これは、何かAccessの設定の問題でしょうか…
たびたびお世話になっています。
メインフォームは非連結です。

このような感じです。
コードは、
Option Compare Database
Private Sub btn_クリア_Click()
Me!cmb_分類 = ""
Me!txb_コード = ""
Me!txb_品名 = ""
Me!cmb_単位 = ""
Me!txb_巾 = ""
Me!txb_長さ = ""
Me!txb_登録日 = ""
Me!txb_更新日 = ""
Me!txb_単価 = ""
Me!txb_改訂前単価 = ""
End Sub
Private Sub btn_登録_Click()
DoCmd.SetWarnings False
DoCmd.OpenQuery "Q_追加T_原材料テーブル"
DoCmd.SetWarnings True
Me!cmb_分類 = Null
Me!txb_コード = Null
Me!txb_品名 = Null
Me!cmb_単位 = Null
Me!txb_巾 = Null
Me!txb_長さ = Null
Me!txb_登録日 = Null
Me!txb_更新日 = Null
Me!txb_単価 = Null
Me!txb_改訂前単価 = Null
DoCmd.GoToControl "cmb_分類"
Me.sub_原材料.Form.Requery
End Sub
Private Sub btn_閉じる_Click()
DoCmd.Close acForm, Me.Name
End Sub
Private Sub Form_AfterUpdate()
End Sub
Private Sub Form_Open(Cancel As Integer)
DoCmd.SelectObject acForm, Me.Name
DoCmd.MoveSize , , 13000, 9200
End Sub
このようになっているのですが、これで大丈夫でしょうか。
よろしくお願いします。
メインフォームは連結ですか、非連結ですか。
非連結の場合、現状のメインフォームのコードを提示してもらえますか。
サブフォームにもコードがあるなら、それも提示してください。
できました!
いつもありがとうございます。もっと勉強します。
サブフォームを再読み込みすればいいでしょう。
メインフォームの登録ボタンのプロシージャの最後に、下記を追加してみてください。
サブフォームコントロール名については下記を参照ください。
サブフォームとサブフォームコントロールの違いとは? - hatena chips
hatenaさん、名前なしさん
ご回答ありがとうございます。
連絡遅くなりまして申し訳ございません。
入力/編集用として考えています。
hatenaさんのアドバイスの条件付き書式を行いましたが、ちらつきが気になってしまいました。
試行錯誤の結果、名前なしさんの考え方を採用しました。
誠にありがとうございました。
今後ともよろしくお願いいたします。
下記でどうでしょう。
?
は1 つの文字を表します。そのほか、いろいろな指定法がありますので、下記を参照されるといいでしょう。
Like 演算子
A.在庫リストをリンクテーブルにしておいて、中身だけ追加・削除を行う
B.エクスポート後PowerShellで在庫リストを削除・リネームする
リスト(テーブル)のような「箱」は頻繁に作成・削除するようなものじゃないので中身だけ操作する仕組みを考えたほうが良いと思います。リンクテーブルにしてしまえばそれほど難しい処理は必要ないでしょう
ただし、リンクテーブルにすると余計なフィールドが追加されたり、ローカルのテーブルで使えてた一部の機能が使えなかったりと癖があるので注意も必要です
※PowerShellによるShare pointの操作はできるという資料をWeb検索から見ているだけでhirotonはまともにやったことはありません
ありがとうございます
結局Sendkeys(Wscript.Shellの方)を使ってペイントに張り付けて名前を付けて保存の処理を一括自動でやる形を取りました
実際バイナリを取ってみたところ元がbmpなのに「イメージ」や「DIB」とは書かれていたのですが
「BM」と書かれていた所が見つからなかったので断念しました
例えば、質問文のテーブルを料理別材料明細テーブルとする。このテーブルから下記のクエリを作る。とりあえず、このクエリをもとに、あれこれやってみるのはどうだろう。
とはいえ、なんだかんだ使っているうちに不具合が出てくるはずなので、諸々手当てが大変にはなる。
式1:◼◼は、式1:DCount(“材料”,”料理別材料明細テーブル”,”[料理別材料明細テーブル].[料理]=‘“ & [料理別材料明細テーブル].[料理] & “‘And [料理別材料明細テーブル].[材料]<=‘“ & [料理別材料明細テーブル].[材料] & “‘“)
式2:◼◼は、式2:IIf([式1]=1,[料理別材料明細テーブル].[料理],””)
やるべき事は慣れる事だと思う。慣れてくれば、逆に明細表示のほうが見やすくなる。明細表示が操作出来ない、いつも見やすくして欲しい、もっと見やすくして欲しい、なんて事になったら、笑うに笑えない。
その帳票フォームは閲覧専用ということでしょうか。
閲覧専用なら、レポートのレポートビュー表示にするのが簡単です。
入力/編集もしたいのなら、条件付き書式で文字色を背景色と同じにするという方法になりますが、重い処理になりますので、ちらついたりして、あまり使いやすいものにはならないと思います。