Dim rsA As Recordset, rsB As Recordset, rsMe As Recordset
Set rsMe = Me.Recordset.Clone
Set rsA = CurrentDb.OpenRecordset("T_A")
Set rsB = CurrentDb.OpenRecordset("T_B")
Do Until rsMe.EOF
If Me!テキストボックス = "なんかやる" Then
Do Until rsA.EOF
Do Until rsB.EOF
If rsA.f1 = rsB.f1 Then
'//なにかする
Exit Do
End If
rsB.MoveNext
Loop
'//なにかする
rsA.MoveNext
Loop
End If
rsMe.MoveNext
Loop
rsA.Close
rsB.Close
rsMe.Close
Dim db As Database
Dim rs As Recordset
Set db = OpenDatabase("C:\daosample\sample.accdb") 'データベースを開く
Set rs = db.OpenRecordset("テーブル名") 'テーブルをレコードセットしてと開く
hatenaさんの最後の回答を見る前に投稿してしまいました。失礼しました。
この場合DAOとの接続宣言は不要なのですね。因みにDim db As DAO.DatabaseやDim rs As DAO.Recordsetの宣言はどういう時に必要なのでしょうか? ネットでのコード見るとこれがあるので、毎回必要と思ってました。
初歩的な事ばかりですみません。
If Not IsDate(Me!納品書日付) Then
MsgBox "納品書日付を入力してください"
Me!納品書日付.SetFocus
Exit Sub
End If
strSQL = _
" UPDATE T納品書まだ分 SET チェック1 = Yes, 納品書日付 = #" & Me!納品書日付入力テキストボックス & "#" & _
" WHERE 納品書入り日 Is Null AND 発注先ID=" & Me!cb発注先選択 & ";"
CurrentDb.Execute strSQL
Me.Refresh 'カレントレコードの編集中によるレコードロック対策
With Me.RecordsetClone
.MoveFirst
Do Until .EOF
.Edit
![T納品書まだ分.チェック1] = True
.Update
.MoveNext
Loop
End With
いろいろ追加
Me.Refresh '現在編集中のレコードを保存する(編集中によるレコードロック対策)
With Me.RecordsetClone
.MoveFirst
Do Until .EOF
If IsNull(![T納品書まだ分.納品書入り日]) Then
.Edit
![T納品書まだ分.チェック1] = True
!納品書日付 = Me!納品書日付入力テキストボックス
.Update
End If
.MoveNext
Loop
End With
SQLを発行するメリットが見つからないので、知識レベルの話としてになりますが、
フォームのボタンを押してSQLを実行するならば、
UPDATE T納品書まだ分 SET T納品書まだ分.チェック1 = Yes
WHERE (((T納品書まだ分.納品書入り日) Is Null) AND ((T納品書まだ分.発注先ID)=[Forms]![F納品書未達処理]![cb発注先選択]));
ブロックプログラミングみたいな事をやりたいのであれば、詳しくないけれど、kintoneやwagbyあたりを調べてみるのはどうかしら。Excelで楽曲作成演奏をやろうとするなら、初音ミクみたいなものを提案しますよね?
ところで、MsAccessを選んだ時点で当たり前のルール(主キー、正規化)を受け入れなければいけません。例えば、運動場でサッカーやろうぜ、でも、足技禁止・手技のみOKルールな!サッカーボール以外もなんでもOKな!、みたいに、何でもありを許したら、それはもはや意味不明な質問です。
追記:コードとは、プログラムコードじゃなくて、商品コードのようなものだったのかしら?
表現があいないなので、正確な状況が把握できません。
サブフォームのレコードソースのテーブルに「コードをいれるフィールドが5つ」あるということでしょうか。
「5つのフィールドいずれかのコードと合致した場合」の合致する値は、メインフォームのテキストボックスに入力するということでしょうか。
メインフォームは連結フォームでしょうか。値を入力するテキストボックスは連結コントロールでしょうか。
もう少し情報を整理して、正確かつ詳細に説明していただけませんか。
下記のような情報は欲しいです。
テーブル名
フィールド名(データ型)
データ例
メインフォームのレコードソース
サブフォームのレコードソース
デザインビューで枠調整をしたのですが上手くいかず、MoveSizeメソッドでやってみたところ期待通りのフォームサイズになりました。
皆さま、ありがとうございました。
DoCmd.MoveSize メソッド (Access)
そのフォームを読み込んだ時にサイズを変更したら良いかな
hirotonさん・skさんもありがとうございます。実際使って試しなががら勉強していく様にします。それにしても奥が深いものですね。でも上手く出来た時は感激しますので頑張っていきます。
色々とありがとうございました。
あとこれも。
オブジェクト変数の作成
変数宣言が必要なのは同一のオブジェクトを操作する必要があるとき、ですかね
間違った実装
hatenaさんも解説されていますが、
Withステートメントを使うとこんな時でも変数宣言をしなくてもよくなります複雑になってくると、どのオブジェクトをWithステートメントで省略したらいいか悩みどころで、省略しないほうが見やすいコードという場合もあります
コードが長くなってくると、
//なにかするのところでWithで省略した記述がrsMeなのか、rsAなのか・・・と本人でも混乱するようになってくるので見やすさ重視で変数を使うなんてこともよくありますApplication.CurrentDb メソッド (Access)
Access の CurrentDB はキャッシュしよう(IT raises ITさん)
CurrentDbについても、本来はとしたり、または
Withステートメントで参照して使用したほうが正しい使い方ができます。上記のような、クエリを複数回実行するのような場合を考えると、実は「CurrentDb.Execute」を繰り返すとは少し違う動作をしますまぁ、よほどのことがない限り、ただクエリを実行するだけであれば
CurrentDb.Executeの1行だけで済ませられるメリットを優先で問題ないので、それで回答している感じですねDBEngine.OpenDatabase メソッドまたは Workspace.OpenDatabase メソッドを使用する場合。
DAO.TableDef オブジェクト型の変数を使用して任意のテーブル定義を参照する場合。
DAO.Recordset オブジェクトの Filter プロパティや Sort プロパティを使用する場合。
Access とは別の Office アプリケーション( Excel や Word などの)の VBA プロジェクトにおいて DAO を使用する場合。
hatenaさん何度も回答ありがとうございます。
大変分かり易い説明をお手数かけました。そういう事だったのですね。納得しました。
色々な情報がごっちゃになっており、混乱してました。
本当にありがとうございました。
あら、そうですね。
となると、RecordsetCloneとSQLの差は縮まりそうですね。あるいは差はないかも。
要検証ですね。時間がとれたらやってみます。
ご指摘ありがとうございます。
まず、AccessのUIでのデータベース操作はDAOを使っています。
クエリ、フォーム、レポートなど、DoCmd系のデータベース操作など。
まずは、これを理解しておいてください。
そこで、
ネットでよくあるコードの一例
これは現在開いてコードを記述しいるAccessファイル以外のAccessファイルを操作するコードになります。具体的には捜査対象は C:\daosample\sample.accdbファイルです。
現在開いてコードを記述しいるAccessファイル内のテーブルを操作する場合は、
Accessファイルを開いた時点で、DAOデータベースは自動で開かれています。よって、OpenDatabaseの記述は不要です。現在開かれているデータベースはCurrentDBで取得できます。
これは変数宣言を省略して下記のように記述してもOKです。
次に、フォームのデータ操作する場合、フォームを開いた時点で、DAOレコードセットも自動で開かれます。フォームのUIでこのレコードセットを操作している仕組みになってます。
ですので、フォームのデータをVBAで操作する場合、OpenRecordsetでわざわざ開く必要はありません。
フォームのレコードセットにアクセスする方法は、Me.Recordset、Me.RecordsetClone、Me.Recordset.Clone があります。それらの違いについては、#4の回答のリンク先で解説しています。
Withステートメントを使用すれば変数宣言も不要になります。
これは、OpenRecordsetの場合も同様に省略することはできますが、
あまり見かけませんね。
こんな感じで理解できたでしょうか。
いまさら改めて見てですけど、「
cmdSQLExecute_Click」のって、
Rnd()がキャッシュ使われて一度しか乱数取得処理入らないんで、ほかのDAO処理のrs!F1 = Rndとやってること違いますねhatenaさんの最後の回答を見る前に投稿してしまいました。失礼しました。
この場合DAOとの接続宣言は不要なのですね。因みにDim db As DAO.DatabaseやDim rs As DAO.Recordsetの宣言はどういう時に必要なのでしょうか? ネットでのコード見るとこれがあるので、毎回必要と思ってました。
初歩的な事ばかりですみません。
ここは、Microsoft Access に関する技術的な質問に対する回答や意見交換をする掲示板なので、掲示板の目的とはやや外れている感はあります。
もっと、適している掲示板はありそうです。
例えば、https://teratail.com/ とか。(かなり辛口の回答がつく可能性はありまずが)
私自身は、プロのプログラマーではなく、本業は別にありますので、この質問には回答できるものは持ち合わせていません。
haenaさん ありがとうございます。そういう()だったのですね。こういう事も認識ないと単純に()なしで記述してしまうので勉強になりました。
別件のhirotonさんからの「処理させていた」のなら「出来ている」のでは?に回答出来ていませんでした。(遅くなりました)
元々更新クエリを数ヶ作成してフォームのフィルターに合わせて実行させていたのです。条件1のときはクエリ1、条件2の時はクエリ2の形で(If分で分岐)。今回色々フォーム変更が必要になり抽出条件が異なるだけの複数のクエリを1つにまとめたいのが目的でした。それを出来るならクエリ作成せずに出来ればと思ったのです。
DAOでSQLを実行するという意味なら、変数宣言は不要です。
CurrentDb はAccessファイルを開いた時点で自動で宣言されてますので。
つまり、下記でOKです。
DAOのレコードセットを利用して更新するということなら、フォームを開いた時点で、すでにDAOレコードセットは開いていて、フォームと連結しています。
そのレコードセットは、Me.Recordset または Me.RecordsetClone でアクセスできます。
ゆえに、やはり、変数宣言は不要です。
レコードセットは宣言してそれに代入してもいいですが、DAO.Database の宣言は不要です。
hirotonさんの#1の回答のコードや、#4の私の回答のリンク先のコードを参照してください。
比較演算子には優先順位があり、ORよりANDの方が優先度が高いです。
ですので、FilterにOR演算子があった場合、意図せぬ結果になる場合があります。
例えば、Filterが A = 1 OR B = 2 の場合、()がないと、
納品書入り日 Is Null AND A = 1 OR B = 2
となり、これは
(納品書入り日 Is Null AND A = 1) OR B = 2
と解釈されます。
意図している下記とは結果が異なります。
納品書入り日 Is Null AND (A = 1 OR B = 2)
hirotonさん hatenaさん ありがとうございます。まずはベタな方法ですが下記で記述しました。
Dim strSQL As String
strSQL =
"UPDATE Q納品書未達F用Rs SET check = Yes " &
"WHERE 納品書入り日 Is Null AND (" & Me.Filter & ");"
DoCmd.SetWarnings False
DoCmd.RunSQL strSQL
DoCmd.SetWarnings True
Me.Refresh
これで一応更新処理はできました。次にDAOでもやってみようと思ってます。それで大変初歩的な質問なのですが先頭に下記を記述でいいでしょうか? これの後にアドバイス頂きましたコードを記述でいいのでしょうか?
'変数宣言
Dim db As DAO.Database
Dim rs As DAO.Recordset
'現在開いているデータベースに接続する。
Set db = CurrentDb
あとこれも初歩的な質問ですが "WHERE 納品書入り日 Is Null AND (" & Me.Filter & ");" のANDの後は()が必要なのですね? 勉強不足ですみません。
出来ればもっといろんな方のご意見を頂戴したいです。
普段ここで回答して下さっている方々や質問者様たちが
どのようなキャリアを積まれているのかも気になります。
先日エージェントとの面談があったのですが、やはりPythonやJava等のオープン系言語が強いとのことでした。
転職準備の一環としてPythonの勉強を始めてみようかと思います。
もし有用な参考書等がありましたら是非ご教示ください。
フォームのレコードセットを使って更新する場合のメリットは、
抽出条件などは考えずに機械的にコーディングできる点。
デメリットは、SQLでの更新よりは処理が遅い点。
ただし、体感できる差がでるのは、よほど件数が多いときです。
下記で処理速度の検証をしていますのでご参考に。
フォームの Recordset, RecorsetClone, RecordSet.Clone の違いとは? - hatena chips
やりたいことを整理すると下記のようなことですか。
帳票フォームのヘッダーに条件用の複数のテキストボックスがあり、その値によりフォームにフィルターをかけている。
VBAで抽出条件式を生成してそれをFilterプロパティに設定している。
表示されているレコードのうち、納品書入り日が未入力(Null)のレコードのチェックボックスにチェックを入れたいということですか。
SQLで更新するなら既に出ていますが、DoCmd.RunSQL か CurrentDb.Execute を使います。
下記でどうでしょう。
フォームのレコードセットをループで回して直接更新してもいいです。(hirotonさんの回答)
Me.Filterの中にはということで、
[cb発注先選択]以外の情報が含まれている可能性があります。この中(Me.Filter)から[cb発注先選択]だけの情報を抜き取りたいということであれば、それは普通やらないです。[cb発注先選択]の情報はそのままMe!cb発注先選択で参照できるので、わざわざMe.Filterから抜き出したりしませんフィルターを何かの手法で直接操作して、その状態でフィルター文字列から何かの情報を取得したいというのは方向性が逆ですね。元となる個別の情報を個別に扱えるような設計を考えましょう
動的にSQLを生成するなら、そのままSQLを実行するコマンドがあります
DoCmd.RunSQL メソッド (Access)
もっといえば、VBAで処理をするならDoCmd オブジェクト (Access)はあまり使う場面がありません。たいていは、より直接的に扱える手法が用意されています。クエリ、SQLの実行であればDatabase.Execute メソッド (DAO)が使いやすいと思います
使用例
納品書日付に入力する値もフォームのテキストボックスで事前に入力しておけば、そのテキストボックスを参照してSQLの文字列に入れ込めばいいですね
改めてですが、フォームに読み込んだデータをフォーム上の作業で更新するならDAO処理のほうが楽ですね。それはそれとして、VBAでSQLを動的に扱うことはあるので、それ用のケーススタディということで
フォームでフィルターを使いつつ、フォームに読み込んでいるデータを扱いたいのなら、DAOとか使ったほうが楽だと思います
フォームに表示されているレコードのチェックボックスを全てYesにする
いろいろ追加
SQLを発行するメリットが見つからないので、知識レベルの話としてになりますが、
フォームのボタンを押してSQLを実行するならば、
このクエリの実行で動作上の不具合はないですよね?
「処理させてましたが」「やり方が分からない」
「処理させていた」のなら「出来ている」のでは?
先日 strSQL = strSQL & " WHERE " & Me.Filter・・・を教えて頂いた者です。
関連のフォームでSQL実行させたい事があるのですが分からないことがでてきました。先日の応用が出来なくて、もどかしいです・・・。やりたい事は部品現品は入荷済みで納品書が未達の分を抽出するフォームを作成しています。そのフォームには仕入先、入荷日、直送先等の抽出条件コンボボックスがあり前回同様 strFilter = mid(strFilter, 6) で抽出出来ています。レコードにはチェックボックスがありチェックYesにしたものだけに後日届いた納品書の日付をフォーム上のテキストボックスから代入して一括入力させたいのです(レコードに1件づつ直接日付入力も可能)。レコード1件づつチェックYesにする事も可能ですがFilter抽出した分にその一括処理をする更新クエリをしているのですが、現状抽出条件毎にクエリを複数作成しています。それを集約させたいのでWHERE " & Me.Filterでしようと思っていたのですが、いざ記述しようとするとどうやって?となってしまったのです。更新クエリのSQLビューは下記です。
UPDATE T納品書まだ分 SET T納品書まだ分.チェック1 = Yes
WHERE (((T納品書まだ分.納品書入り日) Is Null) AND ((T納品書まだ分.発注先ID)=[Forms]![F納品書未達処理]![cb発注先選択]));
この[cb発注先選択]部を Me.Filter にしたいのです。T納品書まだ分.納品書入り日) Is Nullの後にどうコードをつないだらいいのかが分からなくて。一括でチェックYes処理はフォーム上のボタンにDoCmd.OpenQuery・・・で処理させてましたがSQL勉強中なのでそれで処理させようと思ったのですがやり方が分からないのが現状です。
最終的にはチェックYes分に納品書日付を一括代入するボタンもSQL(更新)で処理させたいです。
またこの更新SQLの実行もVBAでどう実行させたらいいのかも分からなくて。
応用力がなく情けないのですが、アドバイスを宜しくお願いします。
hatena様 回答ありがとうございました。
選択クエリと書いてありますが、合計を出しているということは集計クエリですよね。
集計クエリあるいは、集計クエリを含むクエリは更新不可のクエリになります。(Accessの仕様)
よって、それを含む更新クエリは実行できません。ですので、
はAccessの仕様です。
対策としては、下記の3つが考えられます。
「1,2,3をまとめて一発で在庫数を出せ」たクエリからテーブル作成クエリ(あるいは追加クエリ)でテーブルにデータを出力して、そのテーブルを更新クエリにする。
「1,2,3をまとめて一発で在庫数を出せ」たクエリを参照するDLookup関数を更新クエリに埋め込んで実行する。
VBAで「1,2,3をまとめて一発で在庫数を出せ」たクエリとマスタテーブルをそれぞれ差コードセットして開いて、マスターテーブルを先頭からループして、クエリのレコードセットを検索して在庫数を更新していく。
蛇足
データベース設計の基本として計算値はテーブルに格納しないとというのがあります。
今回の場合、「1,2,3をまとめて一発で在庫数を出せ」たクエリがあるのなら、その結果をマスターテーブルに格納する必然性はデータベース的にはないです。
どうしても格納するのなら、入庫、出庫のタイミングで、在庫数を更新するというアプローチが一般的です。
ついでに言うとスクレイピングもpythonでやるほうがいいですよね。SeleniumBasicは2016年以来更新が無いそうですので・・・
「Python」生みの親グイド・ヴァンロッサム氏、マイクロソフトに入社 - ZDNET
こういうことがあったようです。去年ぐらいから Python in Excel というサービスが話題ですね。
りんごは、以前からこの掲示板で人を罵り・卑下・罵倒・誹謗中傷をします。
管理者様、追放してもいいのでは?
throughさん
確かによくPythonは耳にします。
ですがPythonとExcelの関連性を深めようとしているのは知りませんでしたので大変参考になります!
毎度いろんな質問で冷やかすだけで中身のない回答はやめて下さい。
今度私の立てた質問には回答しないでいただけますと幸いです。
そのアプローチは何を参考にしましたか?入庫や出庫の都度、タイムリーに更新しないの?
あと、skさんのコメントを注意して読めていませんでした。すみませんでした。落ち着いて読むと、すごく大事な指摘でした。ありがとうございます。変数の初期値は全く認識ありませんでした。フォーム上のテキストボックス等のコントロール値の入力ありなしではないので If strFilter <> "" Thenでないとダメなのですね。勉強になりました。
転職内定してから悩む事です。絵に描いた餅は趣味で充分じゃない?
ご存じでしょうが、よく言われるのはPythonでしょう。
・TIOBEが毎月発表しているプログラミング言語の人気ランキングで1位
・無料なので、どこの会社でも導入しやすい
・データ分析が得意なので、Accessと関連がある。Microsoftも、PythonをExcelに結び付けたがっている
・豊富な外部ライブラリでいろいろできる
今度休みの日にでも作ってみます。
お答えありがとうございました。
9万件ですか。
そんな件数のデータをコンボボックスに表示させて、ユーザーに選択させようと思ったことはないし、これからも思わないので、試す気になりません。
自分なら、件数を絞り込んで、ユーザーに選択させるUIを考えます。
例えば、複数コンボボックスで絞り込むとか、
ACCESS コンボボックスの絞り込みをする方法 - たすけてACCESS
50音ボタンで絞り込むとか。
名簿管理フォームの設計 - hatena chips
ごめんなさい。100件とかいうのは例のつもりでした。
実際には9万件ぐらいです。以前はなかった症状で、最近気づきました。
なので、8万件台のどこかだとおもいます。症状が発生したのは。
コンボボックスに98件までというような上限はないと思います。
試しに1000件のテーブルを作成してコンボボックスの値集合ソースに設定しましたが、1000件目も表示されて選択できました。
別のクエリとかテーブルを値集合ソースに設定した場合も同じ症状になりますか?