'各コントロールの入力状態をチェックする関数。
'全てのコントロールの値が適切であれば True、そうでなければ False を返す
Private Function InputCheck() As Boolean
On Error GoTo Err_InputCheck
InputCheck = False
'[txtID]のチェック(オートナンバー型の主キー[ID]と照応)
With Me![txtID]
If IsNull(.Value) = True Then
MsgBox "[ID]が入力されていません。", _
vbExclamation, _
"入力エラー"
.SetFocus
Exit Function
End If
If IsNumeric(.Value) = False Then
MsgBox "数値データに変換できない文字列が[ID]に入力されています。", _
vbExclamation, _
"入力エラー"
.SetFocus
Exit Function
End If
If DCount("*", SourceTableName, "[ID]=" & CLng(.Value)) = 0 Then
MsgBox "テーブル[" & SourceTableName & "]上に、[ID]の値が" & CLng(.Value) & "であるレコードは存在しません。", _
vbExclamation, _
"入力エラー"
.SetFocus
Exit Function
End If
End With
'[c1]のチェック(数値型フィールド[F1]と照応)
With Me![c1]
If Nz(.Value, "") <> "" Then
If IsNumeric(.Value) = False Then
MsgBox "数値データに変換できない文字列が[F1]に入力されています。", _
vbExclamation, _
"入力エラー"
.SetFocus
Exit Function
End If
End If
End With
'[c2]のチェック(通貨型フィールド[F2]と照応)
With Me![c2]
If Nz(.Value, "") <> "" Then
If IsNumeric(.Value) = False Then
MsgBox "数値データに変換できない文字列が[F2]に入力されています。", _
vbExclamation, _
"入力エラー"
.SetFocus
Exit Function
End If
End If
End With
'[c3]のチェック(日付/時刻型フィールド[F3]と照応)
With Me![c3]
If Nz(.Value, "") <> "" Then
If IsDate(.Value) = False Then
MsgBox "日時データに変換できない値が[F3]に入力されています。", _
vbExclamation, _
"入力エラー"
.SetFocus
Exit Function
End If
End If
End With
InputCheck = True
'終了処理
Exit_InputCheck:
Exit Function
'エラー時処理
Err_InputCheck:
InputCheck = False
Dim strErrTitle As String
Dim strErrMsg As String
strErrTitle = "実行時エラー (" & Me.Name & ".InputCheck)"
strErrMsg = Err.Number & ": " & Err.Description
Debug.Print strErrTitle
Debug.Print strErrMsg
MsgBox strErrMsg, vbCritical, strErrTitle
End Function
'非連結フォーム[S_1]のフォームモジュール
Option Compare Database
Option Explicit
Private Const SourceTableName As String = "T_1"
'コマンドボタン[cmdUpdate]の[クリック時]イベント
Private Sub cmdUpdate_Click()
On Error GoTo Err_cmdUpdate_Click
'入力チェック処理を実行し、その結果が False だった場合
If InputCheck() = False Then
'このプロシージャを抜ける
Exit Sub
End If
Dim lngResult As VbMsgBoxResult
'実行確認ダイアログを表示し、どのボタンがクリックされたかを受け取る
lngResult = MsgBox("レコードの更新を実行しますか?", _
vbQuestion + vbYesNo + vbDefaultButton2, _
"実行確認")
'[いいえ]ボタンがクリックされた場合
If lngResult = vbNo Then
'このプロシージャを抜ける
Exit Sub
End If
Dim strSQL As String
'UPDATE 文の生成処理を実行し、その結果を変数 strSQL に渡す
strSQL = CreateUpdateStatement()
'生成に失敗した場合
If strSQL = "" Then
'このプロシージャを抜ける
Exit Sub
End If
Debug.Print strSQL
DoCmd.SetWarnings False
'SQL 文の実行
DoCmd.RunSQL strSQL
DoCmd.SetWarnings True
MsgBox "レコードが更新されました。", _
vbInformation, _
"実行完了"
'終了処理
Exit_cmdUpdate_Click:
On Error Resume Next
DoCmd.SetWarnings True
Exit Sub
'エラー時処理
Err_cmdUpdate_Click:
Dim strErrTitle As String
Dim strErrMsg As String
strErrTitle = "実行時エラー (" & Me.Name & ".cmdUpdate_Click)"
strErrMsg = Err.Number & ": " & Err.Description
Debug.Print strErrTitle
Debug.Print strErrMsg
MsgBox strErrMsg, vbCritical, strErrTitle
Resume Exit_cmdUpdate_Click
End Sub
3行までしか入力できないように制限したいということですね。
実現可能かといえば、可能です。
「キークリック時」のイベントプロシージャにコードを記述することになります。
「Enterを押して3行目から4行目に移動するとき」とのことですが、例えば下記のようなときにはどのような動作になることがご希望ですか。
カーソルがテキストの最後ではなく途中にあるときにEnterを押したとき(例えば、3行入力されていて、カーソル位置が2行目の真ん中でEnterを押す)
貼り付けで4行以上のテキストを貼り付けたとき、あるいは、貼り付けた結果4行以上になるとき。
解決済み
大変お世話になっております。
おっしゃる通り、新しいクエリを作成して1から同じように作り直したところうまく処理できるようになりました。
何が原因だったのでしょうか。。。
お騒がせしました。
ここの掲示板はいつも本当に頼りになります。
本当にどうもありがとうございました😌
提示されている情報をもとにサンプルを作成して実行してみましたが、問題なく更新できました。
更新前のテーブル

更新クエリのSQL
上記クエリをナビゲーションウィンドウでのダブルクリックで実行
更新クエリ実行後のテーブル
つまり、提示されている情報での設計に問題はないです。
原因としては、
更新クエリが正しく実行されていないか、
更新後のデータの確認方法が正しくないか、
ぐらいしか思いつきません。
skさんの回答で提示されている情報を開示してください。
また、新規ファイルで、上記のようにテーブルと更新クエリを作成して実行したらどうなるかも試してみて結果を報告してください。
hirotonさん ありがとうございます。なるほど!テーブルに格納が簡単そうですね。全く思いつかないアイデアでした。試してみますね。
変数の適応範囲というものがあります。一般にスコープと言われます
スコープと可視性について
第108回.変数の適用範囲(スコープ,Private,Public)(エクセルの神髄 さん)
モジュールの先頭部分(プロシージャ外)にPublic宣言で変数を宣言すればどこからでも使える変数になります
宣言した後の使い方はほかの変数と同じです。ただし、パブリック変数は、プロシージャレベル変数として同名の変数を別途宣言することが可能なので、使用には注意が必要です
また、実行中に書き換えることのない値であれば変数ではなく定数で宣言するのが望ましいです
宣言場所はどのモジュールでも変わりませんが、システム全体で共有されるものは、標準モジュールを追加して整理すると良いでしょう
ACCESSでこのようなデータを扱うなら、システム環境テーブルを作ってしまうのも手です
T_SYSENV
テーブルに保存してあるデータはDLookup関数で参照できます。また、その機能をユーザー定義関数にしてしまえばそのほかの各モジュールで使う場合も使いやすくなります
テーブルに保存することによって、VBAを編集する必要がなくなる≒ランタイム環境でも(テーブルのデータを編集する機能を作っておけば)設定変更が可能になります
どのような状況下において、どのような操作によってその更新クエリを実行されたのかについて具体的に明記されることをお奨めします。
ナビゲーションウィンドウでその更新クエリを選択して実行した。
その更新クエリがデザインビューで表示されている状態において、[クエリ デザイン]タブ → [結果]グループ → [実行]をクリックした。
[クエリを開く]アクションを呼び出すマクロを実行した。
DoCmd.OpenQuery メソッドを呼び出すプロシージャを実行した。
上記以外の実行操作。
また、更新クエリの実行結果をどのようにして確認されたのかについても明記して下さい。
前述のいずれかの方法によって更新クエリを実行した後、ナビゲーションウィンドウからテーブル[T90]をデータシートビューで開いた。
テーブル[T90]をレコードソースとする帳票フォーム上において、更新クエリを呼び出すイベントマクロ、またはイベントプロシージャを実行した。
上記以外の確認方法。
ありがとうございます。
SQLは名前違ってしまいましたがT90_テストとT90は同じものです
ごめんなさい
実行はしています
どうしても原因が分からなくて。。。
上のSQLだと、2024/05のデータを2024/06に更新したいのですが何か足りませんか?
現在はただ2024/05のデータが表示されるだけで更新がされません
宜しくお願いいたします。
エラーメッセージに限らず、正常に動作するはずの場合と比べておかしな動作をしている部分(動作/表示するはずなのに何も起きないモノ)を洗い出すと良いですよ
テーブルの内容をほかのテーブルの内容で更新する (Access)(Crie Anabukiさん)
正しく「実行」はしていますか?
実行時の確認メッセージは表示されますか?
メッセージに表示される件数は想定したものですか?
「T90」を更新しても「T90_テスト」が更新されることはありませんね
ありがとうございます
年月がテキストで日付が日付時刻型になります
SQLは以下のとおりです
エラーにはならず、なにも更新されません。。。
UPDATE T90 SET T90.年月 = "2024/06", T90.日付 = DateAdd("m",1,[日付]);
宜しくお願いいたします
「T90_テスト」の「年月」と「日付」フィールドのデータ型はそれぞれなんでしょうか。
あと、現状の更新クエリのSQLをコピーしてここに貼り付けてください。
エラーメッセージが表示されるなら、それも提示してください
情報ありがとうございました。
「閉じるときに最適化する」は未チェックでしたので、適用します。
注意点として、フロントエンドに作業用テーブルをおくと、データの追加削除が発生しますので、ゴミがたまりファイルサイズが肥大化するので、定期的にフロントエンドの最適化を実行する必要があります。
あるいは、オプションで閉じるときに最適化してもいいでしょう。
ACCESS 最適化でデータベースの容量を圧縮する方法 - たすけてACCESS
hatenaさん ありがとうございました。OpenArgsで簡単に解決しました。OpenArgsの事は知りませんでした。
こんな便利なことが出来る事を知ることが出来てありがたいです。
お世話になりました。
回答ありがとうございます。
すでに分割はしていましたが、作業用テーブルをフロントに置く考えがありませんでした。(全部まとめて分割していた)
これで解決できると思います。ありがとうございました。
複数ユーザーがデータベースファイルを共有する場合は、「データベースの分割」をして運用することが推奨されています。
Access データベースを分割する - Microsoft サポート
ACCESS データベースを分割して複数人で共有する方法 - たすけてACCESS
サーバーにテーブルのみのデータベースファイルを置きます(バックエンドデータベース)
各クライアントにリンクテーブルとその他のオブジェクトをもつデータベースファイルを置きます(フロントエンドデータペース)
作業用のテーブルはフロントエンドデータベースに置けば、懸念する問題は発生しません。
フォーム上のコマンドボタンから
DoCmd.OpenReportでレポートを開いていると仮定します。DoCmd.OpenReportのOpenArgs引数で値を渡すことができますのでそれを利用するといいでしょう。DoCmd.OpenReport メソッド (Access) | Microsoft Learn
コード例
フォームのコマンドボタンのクリック時
レポートの読み込み時イベント
お返事が遅くなり申し訳ございません。
回答ありがとうございます!
思い通りに背景色をつけられました。
日付の計算はとても一般的なので、標準機能が充実しています
適切な日付関数を選択する
(古いページのせいかなんかめちゃくちゃですね)
3年前の今日と比較する
Date 関数
DateAdd 関数
なお
DateAdd関数は、計算後の日付がその月の末日を超えてしまう場合、その月の末日に丸められます
存在しない月末日付の処理をどうするか?によって計算方法を変える必要がありますので、日付計算を行う場合は「月末」に注意してください
後述の対応をするなら
sk様 回答の表示はそういう事だったのですね。
変更用フォーム[S_1]の非連結コントロールは編集可能なのでユーザーでNullにされる可能性はありますので、変更実行ボタン(それに更新SQLコードを記載)に実行前にNull値には別のコントロール値(元から代入させていた)を代入する方法をとってます。
それぞれの投稿の投稿者アイコンの下にある番号が、このスレッドにおける投稿順を示しています。
私が回答したのは hatena さん( 5 番)よりも後です。
ビギナーさんの投稿( 4 番)に返信する形を取ったため、その階層ツリーのノードとして表示されているだけです。
[フォームA]がテーブル[T_1]をレコードソースとする帳票フォームであるとして、
フォーム[S_1]の各非連結コントロールへの値の代入に際し、[フォームA]のカレントレコードから参照されたいずれかのフィールドの値が元から Null であるケースはないのでしょうか。
少なくとも、フォーム[S_1]のいずれかの非連結コントロールの値がユーザーの操作によって Null にされる可能性はゼロではないはずです。
SK様 失礼しました。hatena様の分の前に詳しい回答を沢山頂いていたのを見落としてました。申し分けありません。
Null値の事は気になってました。説明不足でしたがフォームAのレコードをダブルクリックで変更用のフォームS1が開き、S1で変更しSQLで更新の仕組みにしてます。S1のNULL対策として元々のフォームA値をS1の別のテキストボックスに代入してNULLのテキストボックスにはそれを代入してから更新としてます。
もう1箇所。
1箇所修正。
各コントロールの入力チェック、コントロールの値に応じた条件分岐、
文字列に含まれる引用符のエスケープ処理などを考慮するのであれば、
以上のサンプルのような形となるでしょう。
ただ私個人の見解としては、こういうまどろっこしい文字列連結を行うコードを
記述するより、パラメータクエリを実行するようにした方が良いと思います。
各非連結コントロールの値を「 SQL 文におけるリテラル」として組み込みたい、
という意味でおっしゃっているのであれば、その SQL の実行時において、
いずれかの非連結コントロールの値が Null であることを許容するか否か次第です。
単純に Null 値をそのまま文字列連結させてしまうと、実行時に構文エラーが
発生する可能性が極めて高いでしょう。
hatena様 ありがとうございます。そのコードで問題なく更新できました。VBA内での改行が絡み頭が混乱してました。
一つ教えて頂きたいのですが、SQL内でフォーム値を使う場合も変数と同じ様に&でつなぎ外に出さないといけないのですよね? 質問時の "SET [F1]=[Forms]![S_1]![c1], " & _ は本来間違っているのですね?( "SET [F1]=" & [Forms]![S_1]![c1] & ", " & _ が正しい) たまたま動作していたのですね?
skさんありがとうございます。これに関わる追加処理は現在ありませんので、以前色々処理させた時に間違った事があったと思います。様子みてみます。お世話になりました。
変数は文字列の外(""の外)に出して&で結合すればいいでしょう。
あと、SQL内では日付時刻型は#で囲む、文字列は'で囲みます。
日付をFormatで書式設定しているのは、OSの日付書式設定によってはうまく行かない場合があるのでその対策です。
テキストボックスが未入力だったりした場合のエラー対策は別途必要になります。
SK様 実行はDoCmd.RunSQL strSQL1 でしてます。明らかに間違ってのカンマを削除したら更新できました(初歩的なミスでした。) すみませんでした。あと SQL部の[Forms]![S_1]![c1~C4]を変数にした場合はどう記述するといいでしょうか? これが上手く出来なくて
対象組織の在籍期間Noごとに、役職・職種を持っているのですが、
単純に最新の役職を持つクエリ、最新の職種を持つクエリを作成
(それぞれのクエリで、在籍期間Noでグループ化して、役職・職種を先頭(最後)で抽出)
したものを、こちらのクエリから参照する方法もありますね(全くスマートではないですが)。
SELECT t.氏名, t.組織名, Min(t.発令日) AS 開始日, Max(t.終了日) AS 終了日
FROM アクションテーブル As t
GROUP BY t.氏名, t.組織名, t.在籍期間No
ORDER BY t.氏名, t.在籍期間No;
以上の点についてもお答え下さい。
明らかに誤っているのは「最後の代入式の直後に ","(カンマ) が挿入されている」という点ですが、もし DoCmd オブジェクトの RunSQL メソッドではなく DAO.Database オブジェクト(または ADODB.Connection オブジェクト)の Execute メソッドによって SQL を実行されようとしているのであれば、それとはまた別の理由によって実行に失敗するでしょう。
SK様 T_1のF1は数値型、F2は通貨型、F3は日付型、F4はテキスト型です。
T_1テーブルの上記フィールドを非連結フォームに入力値に更新したいのです。T_1の入力済み値をS_1フォームから変更したいのです。 説明不足でした。
テーブル[T_1]のそれぞれのフィールドのデータ型は何なのか。
その SQL 文をどのオブジェクトのどのメソッドによって実行しようとしているのか。
とりあえず以上の 2 点について明記されることをお奨めします。
[T発注Sub]に100万件以上ものレコードが格納された事実はない。
仮に100万件以上ものレコードが格納されていたとしても、およそ98万件ものレコードがまとめて削除された事実はない。
以上の 2 点を前提とした場合は、原因は「オートナンバー型のフィールドのシード値を変更させ得る操作」が行われたことぐらいしかないと思います。
例えば、[T発注Sub]の[明細ID]のシード値が20000である状態で、次のような追加クエリを実行して新規レコードを1件追加したとします。
その後、[T発注Sub]をデータシートビューで開いて新規レコードを挿入した場合、そのレコードの[明細ID]の値は( 20000 でも 20001 でも 20002 でもなく) 1000001 となり、それ以降に挿入されるレコードについても 1 ずつインクリメントされていきます。
DAO や ADO を介して新規レコードの挿入が実行された場合も同様です。
とりあえず、上記のように「[T発注Sub]の新規レコードの[明細ID]に代入される値を明示的に指定している」追加クエリ、マクロ、プロシージャが存在しないかどうかをご確認されることをお奨めします。
もしそのような操作が実行された形跡も可能性もないのであれば、他の原因を疑われた方がよいでしょう。
Hatenaさま
ありがとうございます。
>アクションテーブルに失効日のフィールドを追加しておいて、SetRenban関数のループ内で発行日の前日を前レコードの失効>日に代入するという処理を追加すればどうでしょう。
movePreviousとかで一旦戻って、Editすることができるんですね。
正直知りませんでした。今回、こちらのほうほうで完璧にできました。
今回、組織コードというおおくくりの組織の配下に、部門、部署というレベルがありまして、
表示する際は、氏名と開始日をもとに、所属歴を参照しては以下組織を持ってきていたのですが、
同じ在籍期間Noでの期間が長いと組織名称が変わっていたりして、終了時点の組織名称を参照する
方法に苦心していましたが、グループ内採番の日付Max値のデータを保持するクエリを作成して、
これを参照することで、Mayuさまのロジックを使わせていただき、なんとかこちらも対応できました。
どうもありがとうございました。
Mayuさま
どうもありがとうございます。
SetSequenceNumber関数、これは凄いものですね!
今後、使えるようにしておきたいです。
私がやったものとは格段に改善しました。
回答有難うございます。
なるほど、大変勉強になり大変助かりました。
有難うございました。