解決したのですね。よかったです。
ちなみに、質問のSQLですが、 サブクエリと親クエリのSQLが演算フィールド以外は同じなのに、わざわざサブクエリにしたということは、ORDER BY句に演算式を重複して記述するのを避けたいという意図でしょうか。
だとしたらORDER BY句にはフィールド名ではなくフィールド番号(何番目のフィールドか)を指定することもできます。それを利用すればサブクエリを使う必要はなくなります。
あと、演算フィールドの式もChoose, DateDiff関数を使えばもう少し簡略化できます。
御参考までにコード例を置いておきます。
[ID], [親番], [売上先], [子番], [支店_営業所], [孫番], [現場名], [府県], [締日], [油種], [直近3ヶ月], [仕入], [売上], [利益], [仕入コード], [仕入先], [単価_ランク_コード], [単価_ランク], [開始(復活)], [終了], [備考1], [備考2], [担当], [車番①], [車番②], [車番③], [車番④], [車番⑤], [車番⑥], [車番⑦], [車番⑧], [車番⑨], [売上先カナ], [支店_営業所カナ], [現場名カナ], [フラグ], [日付コード], [油種コード], [合成キー], [納入先業者名カナ], [親グループカナ], [締め日], [数量料], [更新用フラグ], [更新合成キー], Nz(Choose(DateDiff("m", [直近3ヶ月], DateSerial(Year(Date()), Month(Date()),1)+1,3,2,1),4) AS [並べ順] FROM [Q_直近3ケ月 のコピー] ) AS [サブクエリ] ORDER BY [親番], [子番], [孫番], 46, [油種コード] ASC;
[Q_直近3ケ月 のコピー]を、再度作成しましたら、作動しました。 お騒がせしました。
hatena様、sk様、回答ありがとうございました。
sk様
返信ありがとうございます。 確認しまsたが、フィールドは存在します
これが画像です
こんな感じで、フィールドは存在します
hatena様
同様に全てにおいて、パラメータクエリの表示がされます。 フィールドは、Q_直近3ケ月 のコピーには、すべてあります
FROM [Q_直近3ケ月 のコピー]
[Q_直近3ケ月 のコピー]が選択クエリであるならば、 とりあえずそのクエリのデザイン( SQL )を 再度確認されることをお奨めします。
パラメータダイアログが出るということは、FROM句のテーブルやクエリにその名前のフィールドがないとういことになります。
()や半角空白を含むフィールド名は[]でくくらないと認識できないので、前者のSQLがエラーになるのは当然ですが、後者のSQLでもパラメータが出るということは、[Q_直近3ケ月 のコピー] にその名前のフィールド名がないということになります。[Q_直近3ケ月 のコピー] のフィールド名とSQL内のフィールド名に相違がないのは確実ですか。
下記のサブクエリのSQLのみ実行した場合はどうなりますか。
SELECT [ID], [親番], [売上先], [子番], [支店_営業所], [孫番], [現場名], [府県], [締日], [油種], [直近3ヶ月], [仕入], [売上], [利益], [仕入コード], [仕入先], [単価_ランク_コード], [単価_ランク], [開始(復活)], [終了], [備考1], [備考2], [担当], [車番①], [車番②], [車番③], [車番④], [車番⑤], [車番⑥], [車番⑦], [車番⑧], [車番⑨], [売上先カナ], [支店_営業所カナ], [現場名カナ], [フラグ], [日付コード], [油種コード], [合成キー], [納入先業者名カナ], [親グループカナ], [締め日], [数量料], [更新用フラグ], [更新合成キー], IIf([直近3ヶ月] = DateAdd('m', -2, DateSerial(Year(Date()), Month(Date()), 1)), 1, IIf([直近3ヶ月] = DateAdd('m', -1, DateSerial(Year(Date()), Month(Date()), 1)), 2, IIf([直近3ヶ月] = DateSerial(Year(Date()), Month(Date()), 1), 3, 4))) AS [並べ順] FROM [Q_直近3ケ月 のコピー]
なるほど・・・そういうことですね。 確かにそうすればSQLを使わなくても実行できますね。
ありがとうございます!
デザイナ(クエリデザイン)でGUIで作ってるんじゃないですかね?SQL記述知らなくても作れますよ
ACCESSでクエリといった場合、オブジェクトとして保存されている保存済みのSQL構文のことを指したりもします。ナビゲーションウインドウに表示されるクエリですね。>> 1のカギ括弧で括ったクエリ(「クエリ」)はこちらのオブジェクトとして保存したクエリのことを指しています
ナビゲーションウインドウにどこで使われているかわからないクエリが存在するという問題が減るというのがメリットです
念の為、デバッグの方法を記載します。 以下のやり方が一般的です。
https://tsware.jp/study/vol16/vbabegin_48.htm
今回の場合、ボタンに設定されているVBAのコードにブレークポイントを設定し、そこから1行ずつ追っていく形で動作確認すればいいのかと思います。 1行進ませる場合は「F8」キーを押します。
横からすみません。
基本的なことで申し訳ないのですが、クエリってSQL以外でどうやって使うのでしょうか。
下記のURLの内容は分かるのですが、SQL以外でクエリを使用する方法を知らないので、参考まで教えていただけると助かります。
https://wa3.i-3-i.info/diff199sql.html
Microsoftのドキュメントには
たとえば、 条件 は、多くの場合、WHERE という単語を含まない SQL 式の WHERE 句と同じです。
という記述が頻出します。SQL全般ではないですが、特にWHERE句については記述方法を習得するべきでしょう。また、そのWHERE句がどのように作用するのかという点において、ある程度SQLそのものの知識も必要になるでしょう
また、「クエリ」という実体が不要になるので、たとえばVBAで何かの機能を作るときにクエリが必要になった場合、直接記述することによって余計な「クエリ」を作らずに済むようになります
コマンドボタンから下記のコードを実行するとエラー表示になるということですよね。
DoCmd.OpenReport "請求書", acViewPreview, , "[請求書番号] = " & Me.請求書番号 & ""
このプレビューから印刷するとどうなりますか?
また、コマンドボタンから下記のコードを実行して印刷した場合はどうなりますか?
DoCmd.OpenReport "請求書", acViewNormal, , "[請求書番号] = " & Me.請求書番号 & ""
レポートをデザインビューで開いてレコードソースに、上記のコードと同様の抽出条件を設定して、直接、プレビューしたり、印刷した場合はどうなりますか。
コメント頂きありがとうございます。 >個人的に可能性が高いのは、読み込みデータが無い場合やいままで想定していなかった内容になっている場合でしょうか。 請求書一覧フォーム設置のボタンからでなく、オブジェクトのレポートから直接印刷すれば、住所や金額が問題なく印字されます。デバッグのやり方はわからずすみません。
>レポートのテキストボックスに #Size! とか #Type! と表示されているということですか? 請求書の印刷プレビュー画面の住所や金額、顧客名といった文字や数値データが印字されるところに、エラーの#Size!などが印刷されると言うことです。
>そのテキストボックスのコントロールソースの設定はどうなってますか。 >式が設定してあるなら、式を提示してください。 請求書一覧フォーム設置のボタンからでなく、オブジェクトのレポートから直接印刷すれば、住所や金額が問題なく印字されますので、レポート請求書のテキストボックスは問題ないような気がしますがいかがでしょうか。
金額部分のコントロールソースには =(Sum([明細金額]))+[消費税] の式が設定されています。 ボタンからだと、レポートのデータが入る部分はすべてエラーになっているようです。
現在使用のアクセスファイルだけでなく、過去使用していたアクセスファイルの、同様のボタンを試してみると、今回、エラーになり、バグのようなものなのか、途方にくれています。原因がわかると助かります。
どんな方法で調べてるんでしょう?
クエリを使っているということなので、たくさんのデータから欲しいデータだけを表示しようとしているのだと思いますが、そのような作業は「絞り込み」や「抽出」と呼びます。「検索」だとちょっと別なモノになりますね
この内容はまぁまぁ定番ネタなので、検索エンジンで必要そうなキーワードをならべれば十分な回答が得られると思います。「ACCESS 複数 テキストボックス 抽出」とかそんな感じで
https://www.google.com/search?q=ACCESS 複数 テキストボックス 抽出
「検索」が強すぎてキーワードが「検索」でもいいんですけどね https://www.google.com/search?q=ACCESS 複数 テキストボックス 検索
印刷プレビューの請求書の宛名は(#Size!)、金額部分は(#Type!)とエラーになり、使えなくなくなりました。
レポートのテキストボックスに #Size! とか #Type! と表示されているということですか?
そのテキストボックスのコントロールソースの設定はどうなってますか。 式が設定してあるなら、式を提示してください。
特に何も変更していないのに突然エラー表記されるようになった、ということですね。
個人的に可能性が高いのは、読み込みデータが無い場合やいままで想定していなかった内容になっている場合でしょうか。
デバッグした場合どこでエラーになるか分かるでしょうか。
質問者さんは自己完結されてるようなので、 後から来た閲覧者のために、 大量のデータをテーブルに新規追加する方法の速度に関する、 一般論を置いておきます。
SQLの INSERT INTO ... VALUES ステートメントで1レコードずつ新規追加を繰り返す方法と、 DAOまたはADOの .AddNewメソッドで1レコードずつ新規追加を繰り返す方法では、 後者の方が高速。
理由 INSERT INTO ... VALUES ステートメントでは、1回実行するたびに、レコードセットの生成、破棄が実行される。例えば200レコード追加する場合は、それが200回繰り返される。 .AddNew の場合は、最初にOpenRecorset でレコードセットを生成、200回追加して(.AddNew)後に、最後にレコードセットを破棄(Close)することが可能。生成、破棄は1回のみですむ。
ただし、追加するデータが、Accessのテーブル、CSVデータ、エクセルシート、他データベースのテーブルなどなら、テーブルとして扱うことが可能なので、 INSERT INTO ... SELECT ステートメントを使えば、複数レコード追加でも、1回の実行で可能なので、高速だし、コードもシンプルになる。
結局、いつもの右往左往して自己完結でしたね。そして、貴方の自己完結には脈絡がありません。 もしかして言葉のキャッチボールを知らないのかしら?
T_取込の注文数量を仕分け単位の大きい順で割っていき、最終的に下記のような仕分け表を作成したい
[T_取込]のいずれかのレコードの[注文数量]の値に、最小の仕分け単位(ここでは 100 )未満の端数が含まれることはないのか。
もし最小の仕分け単位未満の端数が含まれる場合、その端数分の数値はどこにも出力しなくてもよいのか。
その仕分け結果を[T_取込]とは別のテーブルに出力できればよいのか。
以上の 3 点次第。
まず、根本的に無理だったのですね。 200程度でも、やはり処理速度には差が出るので、 色々と試してみたのですが、 引数が間違った型、許容範囲外、または競合しています。 というエラーメッセージが出るようになりました。
この原因を見つけ出すのは、かなり困難なので止めます。
脱.Executeは、今後の課題にします。
ありがとうfございました。
上記のようなExcelファイルをフォームのクリック時イベントでダイアログボックスからインポートしたい
ファイルダイアログによって選択された Excel ブック上に 2 つ以上のワークシートが存在していた場合はどのワークシートを参照するのか。
選択されたブック上から参照したワークシートのレイアウト(列の名前/位置)が規定のものとは一致しているか否かを、インポートする直前に検査する必要はないのか。
①1行目(注文数というタイトル)は取込不要 ②2行目をフィールド名として使う ③取り込みたいのは支店番号、支店名・注文数量のフィールドのみ ④取り込みたい行数はA列(支店番号)の最終行まで
今のところ考えられるのは概ね次のいずれかの方法。
「Excel ブックから任意のセル範囲をテーブルとして参照し、任意のフィールドを選択した結果を Access データベース上の任意のテーブルに追加するクエリ( SQL )」を実行する。
「Excel ブックから任意のセル範囲をテーブルとして参照し、任意のフィールドを選択した結果」と「レコードの追加先となるテーブル」をそれぞれ DAO(または ADO )の Recordset オブジェクトとして取得し、前者の全てのレコードを後者に追加するループ処理を実行する。
オートメーションによる Excel アプリケーションの操作と DAO(または ADO )のレコードセットの操作を連携させる。
ただし 1 と 2 の方法の場合、参照元であるセル範囲の各列のデータ型を明示的に指定することはできないため、いずれかのレコードにおいて型変換エラーが発生したり、あるいは意図しないデータ型に変換されてデータが欠損する可能性があります。
現状、どこまでできていて、どこで躓いているのでしょうか。 ある程度コードを書いているのなら、現状のコードを提示してください。 まったくコードが書けていないなら、 とりあえず、調べてみて、できるところまでコードを書くのにチャレンジしてみてください。
ファイル選択ダイアログは下記などをご参考に。
【Access⑬】テーブルにインポートするファイルをダイアログで選択する | Invest edge
Excelの特定範囲のインポートに関しては、下記などをご参考に。
TransferSpreadsheetメソッドのRangeプロパティまとめ | Accessトリビアの泉
ハンドルネームを入力し忘れました。失礼。
INSERT INTOを使ってデータの登録をする
実際にはデータ数が多くなる
"a", "い", "う"は、submtという配列に入っている
実行時エラー 2147217887「要求された名前、または序数に対応する項目がコレクションに見つかりません」
2000件くらいのデータを一括で登録する場合、 .AddNewを利用すると、INSERT INTOを利用した時と比べて、 1/5くらいの時間で処理できてる感じです
₋ 具体的なテストコードと実行時間の測定方法および測定結果が不明。
やはり、根本的な間違いをしているような気がします。
主に足りていないのは、次の 3 つについての理解でしょう。
VBA における配列の扱い方
ADODB.Recordset オブジェクトの AddNew メソッドの使い方
Access データベースにおけるテーブル/クエリの仕様
For i = 1 to 2000 List1(i) = "fact" & i & List1(i) next
adoRs.AddNew List1, List2
仮に adoRs が参照しているのが Access データベース上のテーブルなのであれば、 1 つのテーブルに定義できるフィールドの数の上限は 255 個ですので、 2000 個ものフィールドを持つレコードを追加することなど絶対に不可能です。
INSERT INTOの、100件程度の処理速度を測ってみましたが、 1秒かからないので、コードが簡単に作れることを考えると、 200件程度だったら、これでいいかな~という感じでした。
コードは、 For i = 1 To 200 tex = tex & "fact" & i & "," Next Tn = "算定基礎届" Fn = "(" & "jan" & "," & Left(tex, Len(tex) - 1) & ")" で作ってエラーが出ないので、 List1のフィールド名にも、間違いはなかったはずです。
2000件くらいのデータを一括で登録する場合、 .AddNewを利用すると、INSERT INTOを利用した時と比べて、1/5くらいの時間で処理できてる感じです。
ですが、2000件分のコードを書くのは、間違っているような気がしまして フィールド名をList1に、登録するデータをList2に格納するのですが、 List1 = Array("fact1","fact2","fact3") と2000件書き続けるわけにはいかないので、 変数を利用する必要が出てきます。 しかし、
で処理すると、エラーが出てしまうわけです。 List1(0)には、"jan"の文字列が入るので、1からスタートしています。
List1 に格納されているフィールド名が、追加するテーブルに存在しないという状況のようなのですが、 factに連番を振っているだけなので、 List1(i) = "fact" & i & List1(i) の部分に、なにか致命的な間違いがあるような気がしてますが、原因が分かりません。
ちなみに、主キーのjanを登録してから、updateで残りのデータで更新をかけると 全てsqlで処理しても、コードの簡潔さを考慮すれば、OKレベルではあるのですが、、、、
なんか、負けたようで嫌なのです。 ですが、updateの方が不可が少ないような感じなので、これが正解なのかもしれないのですが、
INSERT INTOを使ってデータの登録をすると、処理時間がかかりすぎるので、.AddNewを利用する場合のトラブルです。
具体的にどのようなコードを書いたのか不明ですが、 追加するデータはどこにどのような形で存在するのでしょうか。
Accessのテーブル、CSVデータ、エクセルシート、あるいは他データベースのテーブルなどなら、INSERT INTOの方がAddNewより高速です。
そうでないなら、どこにどのようなデータがあるのかの説明が必要です。
実行時エラー 2147217887「要求された名前、または序数に対応する項目がコレクションに見つかりません」 というエラーが発生します。
adoRs.AddNew List1, List2 でそのエラーが発生するということですか。
エラーメッセージから推測するに、List1 に格納されているフィールド名が、追加するテーブルに存在しないという状況だと思います。
後だしで、どんどん情報がかわっていくいつものパターンでしょうか? ここはAccessに関する質疑応答、技術的な情報交換の場です。 それを踏まえて、他の閲覧者や後から検索で訪問した人にとって、意味のある情報になるように、Accessでどのように解決するかという観点で、質問していますか?
hirotonさん ありがとうございます。参考になります。DAOはそういうメリットもあるのですね。 まだまだ手探りでしてますので一つ一つ勉強です。 お世話になりました。
DoCmd.RunSQLとCurrentDb.Executeは同じことをするという認識で問題ないです
DoCmd.RunSQL
CurrentDb.Execute
データ処理の流れとしては確認できたような手順で行えばいいですが、hatenaさん指摘のように、それを「保証する」のもデータベースでは必要になりますね
DAOはコード記述になるので、自動整形や構文エラーチェックが使えたりしますが、SQL実行は文字列を渡すだけなのでその文字列が正しいかどうかは実行してみないと分からないという違いがありますね 単純な記述部分でも、SQLはフィールドを並べてから値を並べるので、フィールドと値の対応が分かりにくいのは扱いにくいところだと思っています
hatenaさん ありがとうございます。回答頂いたコードで動作確認取れました。 DAOはした事がありませんでしたが勉強して行きます。場合によりますが慣れたらSQLよりも分かり易いかもしれません。 お世話になりました。
正規化できるまでのつなぎとして「10行複製のボタン」をとりあえず作成するなら、下記のようなイメージ。
複製するフィールドは F1, F2, F3 と仮定。 フォームのカレントレコードの値を10レコード分複製
Public Sub Sample() Dim rs As DAO.Recordset, i As Long Set rs = Me.RecordsetClone For i = 1 To 10 rs.AddNew rs!F1 = Me.F1 rs!F2 = Me.F2 rs!F3 = Me.F3 rs.Update Next End Sub
下記のような感じになります。
'前略 Dim rs As DAO.Recordset, MainId As Long Set rs = CurrentDb.OpenRecordset("T支給Main", dbOpenTable, dbAppendOnly) rs.AddNew rs!支給日付 = dt1 'dt1 はDate型 rs!支給先選択 = sikyusaki rs!支給方法選択 = 1 rs!部材発送はまだ = -1 MainId = rs!メインID '生成されたメインID rs.Update rs.Close Dim strSQL As String strSQL = "INSERT INTO [T支給Sub] ([メインID], [部品ID], [支給数], [用意状況Memo]) " & "SELECT " & MainId & " As [メインID], [材料支給ファイル対象ID], [注残の合計], [memo] " & _ "FROM [T部材発注accessからIN_直送分];" CurrentDb.Execute strSQL, dbFailOnError
hatenaさん ありがとうございます。奥の深いものですね。勉強になります。 因みにメインテーブルへDAOで1レコード追加するにはどんなコードになりますでしょうか?
一対多のテーブルの新規追加するする場合は、じぶんなら下記のようにします。
メインテーブルへの追加(1レコード)はDAOを使って追加。その時にそのレコードのメインID(オートナンバー型)を変数に格納しておく。
サブテーブルへの追加はSQLをDAOでExcuteメソッドで実行して追加。その時に、メインIDは上記の変数のものを利用。
なぜ、DAOを使うかというと、 DoCmd.RunSQLは非同期で実行されるので、SQLの実行が終了する前に次の処理が実行される可能性があるので、それを避けるためです。
また、メインIDをDMaxで取得する場合、マルチユーザーで同時追加する場合に、自分のメインIDでない可能性も捨てきれないので。
メインに追加するのは1レコードだけなのでこのような可能性は低いですが、コード的には大差ないのでより安全性の高いものにしてます。
hirotonさん ありがとうございます。指摘通りに変更したら上手く出来ました。確かにそのままだと メインID = DMax("[支給ID]", "T支給Main") はメインテーブルに追加前に取得されますね。初歩的なミスでした。strSQL3の内容も2の追加に入れることが出来ました。最終定期にstrSQLを1,2分けずに strSQL =1の処理⇒CurrentDb.Execute strSQL, dbFailOnErrorで実行、DMaxの取得、 strSQL =2の処理⇒CurrentDb.Execute strSQL, dbFailOnErrorで実行にしました。SQL実行するのに DoCmd.RunSQLしか使った事がなかったのですが CurrentDb.Execute strSQL, dbFailOnError (ネットからの情報で知ったコード) は同じ動きをする認識でいいでしょうか? これはアクションSQLのみ有効と思いますが。別な質問になりすみません。
メインID = DMax("[支給ID]", "T支給Main") '追加したメインレコードのID取得
そして DoCmd.RunSQL strSQL1~3で実行としてます。
strSQL1が実行されて初めて新しいメインIDが作られるので、今の手順では追加前の最終のIDを取るだけですね。コードを記述した通りにプログラムが動いています
strSQL1
最新のメインIDが作られてから(DoCmd.RunSQL strSQL1を実行してから)メインIDの取得を行いましょう
DoCmd.RunSQL strSQL1
ついでに、strSQL2の実行前にメインIDが取得できるのでstrSQL2にメインIDを入れることができます。[用意状況Memo]やstrSQL3による追加のアップデート作業も不要ですね
strSQL2
[用意状況Memo]
strSQL3
「10行複製のボタン」は簡単に作れますよ。それだけのものに意味がないのでその方法を誰も回答しないだけで
ACCESSはデータベースソフトなので、それを逸脱するような作りはいろいろな問題があります。それをやりたいならExcelでやったほうが簡単だし問題も少ないです(目的は別にして手法だけならという意味で)
なぜAccessなのか、データベースとはどういうものなのか、データベース化することによってどのようなメリットがあるのか、Accessでどうこうする以前の「情報をどのように扱うべきか」という理論レベルの知識がもっと必要ですね
具体的に言うなら「なぜExcelではだめなのか」を考えてみましょう そのうえで、それでも「10行複製のボタン」が欲しいとなるなら、もしかするとAccessという選択が間違いなのかもしれませんよ
Accessのテーブルやクエリのデータを貼り付ける場合は下記で、Markdown書式のテーブルに変換して貼り付けてください。
Markdown Tables generator
解決したのですね。よかったです。
ちなみに、質問のSQLですが、
サブクエリと親クエリのSQLが演算フィールド以外は同じなのに、わざわざサブクエリにしたということは、ORDER BY句に演算式を重複して記述するのを避けたいという意図でしょうか。
だとしたらORDER BY句にはフィールド名ではなくフィールド番号(何番目のフィールドか)を指定することもできます。それを利用すればサブクエリを使う必要はなくなります。
あと、演算フィールドの式もChoose, DateDiff関数を使えばもう少し簡略化できます。
御参考までにコード例を置いておきます。
[Q_直近3ケ月 のコピー]を、再度作成しましたら、作動しました。
お騒がせしました。
hatena様、sk様、回答ありがとうございました。
sk様
返信ありがとうございます。
確認しまsたが、フィールドは存在します
これが画像です
こんな感じで、フィールドは存在します
hatena様
同様に全てにおいて、パラメータクエリの表示がされます。
フィールドは、Q_直近3ケ月 のコピーには、すべてあります
[Q_直近3ケ月 のコピー]が選択クエリであるならば、
とりあえずそのクエリのデザイン( SQL )を
再度確認されることをお奨めします。
パラメータダイアログが出るということは、FROM句のテーブルやクエリにその名前のフィールドがないとういことになります。
()や半角空白を含むフィールド名は[]でくくらないと認識できないので、前者のSQLがエラーになるのは当然ですが、後者のSQLでもパラメータが出るということは、[Q_直近3ケ月 のコピー] にその名前のフィールド名がないということになります。[Q_直近3ケ月 のコピー] のフィールド名とSQL内のフィールド名に相違がないのは確実ですか。
下記のサブクエリのSQLのみ実行した場合はどうなりますか。
なるほど・・・そういうことですね。
確かにそうすればSQLを使わなくても実行できますね。
ありがとうございます!
デザイナ(クエリデザイン)でGUIで作ってるんじゃないですかね?SQL記述知らなくても作れますよ
ACCESSでクエリといった場合、オブジェクトとして保存されている保存済みのSQL構文のことを指したりもします。ナビゲーションウインドウに表示されるクエリですね。>> 1のカギ括弧で括ったクエリ(「クエリ」)はこちらのオブジェクトとして保存したクエリのことを指しています
ナビゲーションウインドウにどこで使われているかわからないクエリが存在するという問題が減るというのがメリットです
念の為、デバッグの方法を記載します。
以下のやり方が一般的です。
https://tsware.jp/study/vol16/vbabegin_48.htm
今回の場合、ボタンに設定されているVBAのコードにブレークポイントを設定し、そこから1行ずつ追っていく形で動作確認すればいいのかと思います。
1行進ませる場合は「F8」キーを押します。
横からすみません。
基本的なことで申し訳ないのですが、クエリってSQL以外でどうやって使うのでしょうか。
下記のURLの内容は分かるのですが、SQL以外でクエリを使用する方法を知らないので、参考まで教えていただけると助かります。
https://wa3.i-3-i.info/diff199sql.html
Microsoftのドキュメントには
という記述が頻出します。SQL全般ではないですが、特にWHERE句については記述方法を習得するべきでしょう。また、そのWHERE句がどのように作用するのかという点において、ある程度SQLそのものの知識も必要になるでしょう
また、「クエリ」という実体が不要になるので、たとえばVBAで何かの機能を作るときにクエリが必要になった場合、直接記述することによって余計な「クエリ」を作らずに済むようになります
コマンドボタンから下記のコードを実行するとエラー表示になるということですよね。
このプレビューから印刷するとどうなりますか?
また、コマンドボタンから下記のコードを実行して印刷した場合はどうなりますか?
レポートをデザインビューで開いてレコードソースに、上記のコードと同様の抽出条件を設定して、直接、プレビューしたり、印刷した場合はどうなりますか。
コメント頂きありがとうございます。
>個人的に可能性が高いのは、読み込みデータが無い場合やいままで想定していなかった内容になっている場合でしょうか。
請求書一覧フォーム設置のボタンからでなく、オブジェクトのレポートから直接印刷すれば、住所や金額が問題なく印字されます。デバッグのやり方はわからずすみません。
>レポートのテキストボックスに #Size! とか #Type! と表示されているということですか?
請求書の印刷プレビュー画面の住所や金額、顧客名といった文字や数値データが印字されるところに、エラーの#Size!などが印刷されると言うことです。
>そのテキストボックスのコントロールソースの設定はどうなってますか。
>式が設定してあるなら、式を提示してください。
請求書一覧フォーム設置のボタンからでなく、オブジェクトのレポートから直接印刷すれば、住所や金額が問題なく印字されますので、レポート請求書のテキストボックスは問題ないような気がしますがいかがでしょうか。
金額部分のコントロールソースには =(Sum([明細金額]))+[消費税] の式が設定されています。
ボタンからだと、レポートのデータが入る部分はすべてエラーになっているようです。
現在使用のアクセスファイルだけでなく、過去使用していたアクセスファイルの、同様のボタンを試してみると、今回、エラーになり、バグのようなものなのか、途方にくれています。原因がわかると助かります。
どんな方法で調べてるんでしょう?
クエリを使っているということなので、たくさんのデータから欲しいデータだけを表示しようとしているのだと思いますが、そのような作業は「絞り込み」や「抽出」と呼びます。「検索」だとちょっと別なモノになりますね
この内容はまぁまぁ定番ネタなので、検索エンジンで必要そうなキーワードをならべれば十分な回答が得られると思います。「ACCESS 複数 テキストボックス 抽出」とかそんな感じで
https://www.google.com/search?q=ACCESS 複数 テキストボックス 抽出
「検索」が強すぎてキーワードが「検索」でもいいんですけどね
https://www.google.com/search?q=ACCESS 複数 テキストボックス 検索
レポートのテキストボックスに #Size! とか #Type! と表示されているということですか?
そのテキストボックスのコントロールソースの設定はどうなってますか。
式が設定してあるなら、式を提示してください。
特に何も変更していないのに突然エラー表記されるようになった、ということですね。
個人的に可能性が高いのは、読み込みデータが無い場合やいままで想定していなかった内容になっている場合でしょうか。
デバッグした場合どこでエラーになるか分かるでしょうか。
質問者さんは自己完結されてるようなので、
後から来た閲覧者のために、
大量のデータをテーブルに新規追加する方法の速度に関する、
一般論を置いておきます。
SQLの INSERT INTO ... VALUES ステートメントで1レコードずつ新規追加を繰り返す方法と、
DAOまたはADOの .AddNewメソッドで1レコードずつ新規追加を繰り返す方法では、
後者の方が高速。
理由
INSERT INTO ... VALUES ステートメントでは、1回実行するたびに、レコードセットの生成、破棄が実行される。例えば200レコード追加する場合は、それが200回繰り返される。
.AddNew の場合は、最初にOpenRecorset でレコードセットを生成、200回追加して(.AddNew)後に、最後にレコードセットを破棄(Close)することが可能。生成、破棄は1回のみですむ。
ただし、追加するデータが、Accessのテーブル、CSVデータ、エクセルシート、他データベースのテーブルなどなら、テーブルとして扱うことが可能なので、 INSERT INTO ... SELECT ステートメントを使えば、複数レコード追加でも、1回の実行で可能なので、高速だし、コードもシンプルになる。
結局、いつもの右往左往して自己完結でしたね。そして、貴方の自己完結には脈絡がありません。
もしかして言葉のキャッチボールを知らないのかしら?
[T_取込]のいずれかのレコードの[注文数量]の値に、最小の仕分け単位(ここでは 100 )未満の端数が含まれることはないのか。
もし最小の仕分け単位未満の端数が含まれる場合、その端数分の数値はどこにも出力しなくてもよいのか。
その仕分け結果を[T_取込]とは別のテーブルに出力できればよいのか。
以上の 3 点次第。
まず、根本的に無理だったのですね。
200程度でも、やはり処理速度には差が出るので、
色々と試してみたのですが、
引数が間違った型、許容範囲外、または競合しています。
というエラーメッセージが出るようになりました。
この原因を見つけ出すのは、かなり困難なので止めます。
脱.Executeは、今後の課題にします。
ありがとうfございました。
ファイルダイアログによって選択された Excel ブック上に 2 つ以上のワークシートが存在していた場合はどのワークシートを参照するのか。
選択されたブック上から参照したワークシートのレイアウト(列の名前/位置)が規定のものとは一致しているか否かを、インポートする直前に検査する必要はないのか。
今のところ考えられるのは概ね次のいずれかの方法。
「Excel ブックから任意のセル範囲をテーブルとして参照し、任意のフィールドを選択した結果を Access データベース上の任意のテーブルに追加するクエリ( SQL )」を実行する。
「Excel ブックから任意のセル範囲をテーブルとして参照し、任意のフィールドを選択した結果」と「レコードの追加先となるテーブル」をそれぞれ DAO(または ADO )の Recordset オブジェクトとして取得し、前者の全てのレコードを後者に追加するループ処理を実行する。
オートメーションによる Excel アプリケーションの操作と DAO(または ADO )のレコードセットの操作を連携させる。
ただし 1 と 2 の方法の場合、参照元であるセル範囲の各列のデータ型を明示的に指定することはできないため、いずれかのレコードにおいて型変換エラーが発生したり、あるいは意図しないデータ型に変換されてデータが欠損する可能性があります。
現状、どこまでできていて、どこで躓いているのでしょうか。
ある程度コードを書いているのなら、現状のコードを提示してください。
まったくコードが書けていないなら、
とりあえず、調べてみて、できるところまでコードを書くのにチャレンジしてみてください。
ファイル選択ダイアログは下記などをご参考に。
【Access⑬】テーブルにインポートするファイルをダイアログで選択する | Invest edge
Excelの特定範囲のインポートに関しては、下記などをご参考に。
TransferSpreadsheetメソッドのRangeプロパティまとめ | Accessトリビアの泉
ハンドルネームを入力し忘れました。失礼。
₋ 具体的なテストコードと実行時間の測定方法および測定結果が不明。
主に足りていないのは、次の 3 つについての理解でしょう。
VBA における配列の扱い方
ADODB.Recordset オブジェクトの AddNew メソッドの使い方
Access データベースにおけるテーブル/クエリの仕様
仮に adoRs が参照しているのが Access データベース上のテーブルなのであれば、
1 つのテーブルに定義できるフィールドの数の上限は 255 個ですので、
2000 個ものフィールドを持つレコードを追加することなど絶対に不可能です。
INSERT INTOの、100件程度の処理速度を測ってみましたが、
1秒かからないので、コードが簡単に作れることを考えると、
200件程度だったら、これでいいかな~という感じでした。
コードは、
For i = 1 To 200
tex = tex & "fact" & i & ","
Next
Tn = "算定基礎届"
Fn = "(" & "jan" & "," & Left(tex, Len(tex) - 1) & ")"
で作ってエラーが出ないので、
List1のフィールド名にも、間違いはなかったはずです。
やはり、根本的な間違いをしているような気がします。
2000件くらいのデータを一括で登録する場合、
.AddNewを利用すると、INSERT INTOを利用した時と比べて、1/5くらいの時間で処理できてる感じです。
ですが、2000件分のコードを書くのは、間違っているような気がしまして
フィールド名をList1に、登録するデータをList2に格納するのですが、
List1 = Array("fact1","fact2","fact3")
と2000件書き続けるわけにはいかないので、
変数を利用する必要が出てきます。
しかし、
For i = 1 to 2000
List1(i) = "fact" & i & List1(i)
next
で処理すると、エラーが出てしまうわけです。
List1(0)には、"jan"の文字列が入るので、1からスタートしています。
List1 に格納されているフィールド名が、追加するテーブルに存在しないという状況のようなのですが、
factに連番を振っているだけなので、
List1(i) = "fact" & i & List1(i)
の部分に、なにか致命的な間違いがあるような気がしてますが、原因が分かりません。
ちなみに、主キーのjanを登録してから、updateで残りのデータで更新をかけると
全てsqlで処理しても、コードの簡潔さを考慮すれば、OKレベルではあるのですが、、、、
なんか、負けたようで嫌なのです。
ですが、updateの方が不可が少ないような感じなので、これが正解なのかもしれないのですが、
具体的にどのようなコードを書いたのか不明ですが、
追加するデータはどこにどのような形で存在するのでしょうか。
Accessのテーブル、CSVデータ、エクセルシート、あるいは他データベースのテーブルなどなら、INSERT INTOの方がAddNewより高速です。
そうでないなら、どこにどのようなデータがあるのかの説明が必要です。
adoRs.AddNew List1, List2 でそのエラーが発生するということですか。
エラーメッセージから推測するに、List1 に格納されているフィールド名が、追加するテーブルに存在しないという状況だと思います。
後だしで、どんどん情報がかわっていくいつものパターンでしょうか?
ここはAccessに関する質疑応答、技術的な情報交換の場です。
それを踏まえて、他の閲覧者や後から検索で訪問した人にとって、意味のある情報になるように、Accessでどのように解決するかという観点で、質問していますか?
hirotonさん ありがとうございます。参考になります。DAOはそういうメリットもあるのですね。
まだまだ手探りでしてますので一つ一つ勉強です。
お世話になりました。
DoCmd.RunSQLとCurrentDb.Executeは同じことをするという認識で問題ないですデータ処理の流れとしては確認できたような手順で行えばいいですが、hatenaさん指摘のように、それを「保証する」のもデータベースでは必要になりますね
DAOはコード記述になるので、自動整形や構文エラーチェックが使えたりしますが、SQL実行は文字列を渡すだけなのでその文字列が正しいかどうかは実行してみないと分からないという違いがありますね
単純な記述部分でも、SQLはフィールドを並べてから値を並べるので、フィールドと値の対応が分かりにくいのは扱いにくいところだと思っています
hatenaさん ありがとうございます。回答頂いたコードで動作確認取れました。
DAOはした事がありませんでしたが勉強して行きます。場合によりますが慣れたらSQLよりも分かり易いかもしれません。
お世話になりました。
正規化できるまでのつなぎとして「10行複製のボタン」をとりあえず作成するなら、下記のようなイメージ。
複製するフィールドは F1, F2, F3 と仮定。
フォームのカレントレコードの値を10レコード分複製
下記のような感じになります。
hatenaさん ありがとうございます。奥の深いものですね。勉強になります。
因みにメインテーブルへDAOで1レコード追加するにはどんなコードになりますでしょうか?
一対多のテーブルの新規追加するする場合は、じぶんなら下記のようにします。
メインテーブルへの追加(1レコード)はDAOを使って追加。その時にそのレコードのメインID(オートナンバー型)を変数に格納しておく。
サブテーブルへの追加はSQLをDAOでExcuteメソッドで実行して追加。その時に、メインIDは上記の変数のものを利用。
なぜ、DAOを使うかというと、
DoCmd.RunSQLは非同期で実行されるので、SQLの実行が終了する前に次の処理が実行される可能性があるので、それを避けるためです。
また、メインIDをDMaxで取得する場合、マルチユーザーで同時追加する場合に、自分のメインIDでない可能性も捨てきれないので。
メインに追加するのは1レコードだけなのでこのような可能性は低いですが、コード的には大差ないのでより安全性の高いものにしてます。
hirotonさん ありがとうございます。指摘通りに変更したら上手く出来ました。確かにそのままだと メインID = DMax("[支給ID]", "T支給Main") はメインテーブルに追加前に取得されますね。初歩的なミスでした。strSQL3の内容も2の追加に入れることが出来ました。最終定期にstrSQLを1,2分けずに strSQL =1の処理⇒CurrentDb.Execute strSQL, dbFailOnErrorで実行、DMaxの取得、 strSQL =2の処理⇒CurrentDb.Execute strSQL, dbFailOnErrorで実行にしました。SQL実行するのに DoCmd.RunSQLしか使った事がなかったのですが CurrentDb.Execute strSQL, dbFailOnError (ネットからの情報で知ったコード) は同じ動きをする認識でいいでしょうか? これはアクションSQLのみ有効と思いますが。別な質問になりすみません。
strSQL1が実行されて初めて新しいメインIDが作られるので、今の手順では追加前の最終のIDを取るだけですね。コードを記述した通りにプログラムが動いています最新のメインIDが作られてから(
DoCmd.RunSQL strSQL1を実行してから)メインIDの取得を行いましょうついでに、
strSQL2の実行前にメインIDが取得できるのでstrSQL2にメインIDを入れることができます。[用意状況Memo]やstrSQL3による追加のアップデート作業も不要ですね「10行複製のボタン」は簡単に作れますよ。それだけのものに意味がないのでその方法を誰も回答しないだけで
ACCESSはデータベースソフトなので、それを逸脱するような作りはいろいろな問題があります。それをやりたいならExcelでやったほうが簡単だし問題も少ないです(目的は別にして手法だけならという意味で)
なぜAccessなのか、データベースとはどういうものなのか、データベース化することによってどのようなメリットがあるのか、Accessでどうこうする以前の「情報をどのように扱うべきか」という理論レベルの知識がもっと必要ですね
具体的に言うなら「なぜExcelではだめなのか」を考えてみましょう
そのうえで、それでも「10行複製のボタン」が欲しいとなるなら、もしかするとAccessという選択が間違いなのかもしれませんよ