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発注先選択]));
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件目も表示されて選択できました。
別のクエリとかテーブルを値集合ソースに設定した場合も同じ症状になりますか?
すみません。
昔作ったので勘違いしてました。コンボボックスですね。
余計なお世話かもしれませんが、若いのであればこれを読んでおく価値があるかもしれませんよ。
社内SEで定年まで安泰とは言い切れない、勉強が一生報われる職が別にあるかもしれないと思いました。
中国IT業界の急激な変革で消えるエンジニアの悲痛な叫び
hirotonさん ありがとうございました。参考になります。
SQLビューは確かに参照が多かったり抽出条件が多いと非常に見にくくなりますね。
初歩的な事に何度もコメント頂きありがとうございました。
「レコードセット出来れば」がちょっとどういったことを指しているのか分からないので、「それ」が重要かどうかは何とも言えないですね
まぁ、クエリだけではどうにもうまくいかない、手間(時間)がかかるケースに出くわしたらDAOを思い出したらいいでしょう
とくにはないです。SQLビューで開くと汚いとか、SQLビューでしか編集できないような複雑なクエリを修正しようとすると汚くてまず整形からやらないとやってられないとか、VBAで動的なSQLを生成しようと思ってベースのSQL文を作るために使うとまぁまぁ修正作業が必要とかです
あとは、稀に、手書きのほうが圧倒的に簡素な記述がデザインビューで作ると、ちょっとこれは作るのに苦労するなって形になってしまうことがないわけでもありません
こういうのはSQLを難しいと思ってしまう原因になったりもするので、SQLビューの記述は絶対ではないというのは頭に置いておくといいかもしれません
リストボックスあるいはコンボボックスではなくて、テキストボックスですか。
テキストボックスだとしたら、クエリのデータをどのようにテキストボックスに表示してますか。
hirotonさん度々ありがとうございます。ネットでDAO処理で”レコードセット出来ればこっちのもの”というコメントを見た事がありますが、それがまず重要なのですね?
あと『クエリを保存すると自動整形される/されてしまう点には注意が必要です』とありましたが自動整形されると何が問題になることがあるのでしょうか?
大抵はクエリによる代替手法がありますね。データベースというのはそういうものなので
たとえば、今回の例でなら、既に回答した部分ですが、機能が一か所にまとめられるというのはそれだけでメリットになります(データベース的なメリットではないですが)
また、出力先のExcelの書式が決まっていて特定の位置に出力したいなんていうときには、「貼り付け先を指定できる」や、それこそ「レコード、フィールドごとに出力先を指定できる」というような細かい作業ができます(これも、データベースではないモノを相手にする場合という視点ですね)
そのほか、よくありそうなのは、ACCESSで連番を使いたいなんて場合があります
グループ毎連番を自動入力する関数(hatena chipsさん)
クエリだけでも実現可能ですが、データの量によってはより高速な手法が望まれることがあります
基本的にACCESSはデータを縦方向に処理するのを苦手とするので、「前後のレコードの関係性から何かの処理をする」様な場合はDAOのほうが向いていることがあります
あとは、データ処理を伴いつつ複数のレコードを処理する必要が出る場合なんかも、都度クエリを実行するよりはDAOの処理を組んだほうが良くなったりします
例えば、生産管理を考えたとき、在庫管理をしつつ、不足分は発注するのような処理は状態によるパターンが複数あり、クエリだけで処理をするのは難しくなったりします
hirotonさん hatenaさん ありがとうございました。こつこつ勉強してステップアップ出来たらいいと思ってます。
今回の処理も今までクエリを沢山作ってたで画期的でした。
どういうときにDAOが必要かわかっていませんが(SQLだけで出来る事多いので)、色々と勉強します。
本当にありがとうございました。