なるほど・・・そういうことですね。 確かにそうすれば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という選択が間違いなのかもしれませんよ
何度もありがとうございます。 とりあえず、10行複製のボタンは簡単には出来ないんだなぁ、という事がわかりました。 規定値設定ですが、1月の伝票が150行続く時もあれば、その次には2月のもの、等バラバラなので、なかなか…という感じです。 正規化については、時間を見つけて取り組んでみたいと思います。 ありがとうございました。
例えば日付と項目等をレコード複製しておいて、金額と備考欄等をExcelから貼り付け、というふうにしています。
ID →オートナンバー 支払日 →複製したい場合とExcelから張り付ける場合がある 支払種別 →複製したい場合とExcelから張り付ける場合がある 支払先名 →複製したい場合とExcelから張り付ける場合がある 部門名 →空白でok 施設名 →複製したい場合とExcelから張り付ける場合がある 金額 →Excelから貼り付け 支払方法 →複製 該当月 →複製したい場合とExcelから張り付ける場合がある 備考 複製したい場合とExcelから張り付ける場合がある
この辺から推測するに、 支払伝票的なものをAccessで管理したいという印象。
だとすると、扱うデータは、 共通するデータ(ヘッダー項目)とレコード毎に変化するデータ(明細データ)に分けられると思います。
データベースは同じデータを繰り返し格納しないという設計原則があります。 繰り返されるデータ(今回ならヘッダー項目)と変化するデータ(今回なら明細データ)は別テーブルにすることになります。 このような設計を「正規化」といいます。いちど「正規化」でWEB検索してみてください。
例えば、Accessで解説しているページとしては下記あたりを参考に。
正規化とは - もう一度学ぶMS-Access
アクセスデータベース設計の基本(正規化) | ExcelとAccessの学習室
正規化されたテーブルなら同じデータを複製する必要はなくなります。 また、Accessでは正規化されたデータを入力する場合は、メイン/サブフォーム形式の入力フォームを使うのが一般的です。 メインフォームでヘッダー項目を入力、サブフォームで明細データを入力というUIになります。
Accessのフォームのメイン/サブフォームとは | できるネット
パターンが多すぎるようなら、中間作業をExcelでやってしまえばいいんじゃないかと思ってしまいますね。1行コピーして100行選択して貼り付けで100行分データが出来上がりです Accessでレコードを選択してコピーからExcelに貼り付けで1行の元データも作成できますし
パターンが網羅できるようなら、すべての手作業パターンをそっくりそのままコード化してしまえば良いでしょう
"DefaultValue/既定値" プロパティ
新規レコードで、各フィールドごとに初期値を設定しておくことができます。わざわざレコードを複製しなくても、単純な入力作業が必要なところだけの入力で済みます
例えば、入力フォームに「規定値設定」ボタンを配置し、以下プロパティを設定します
名前 |規定値設定 クリック時|[イベント プロシージャ]
[イベント プロシージャ]を設定した欄の右端の[...]をクリックするとVBEが立ち上がります 次のような表記になっているので、コードを記述します
Private Sub 規定値設定_Click() End Sub
↓
Private Sub 規定値設定_Click() Me!支払日.DefaultValue = Me!支払日 Me!支払種別.DefaultValue = Me!支払種別 End Sub
一度フォームを閉じて保存したあと、再度フォームを開いて「規定値設定」ボタンを押してみてください。新規レコードの「支払日」「支払種別」が、「規定値設定」ボタンを押したレコードの内容になります
accessの項目は以下です。
・ひとつひとつ入力していく場合 このいくつかの項目の内容が同じ場合は、1行複写するボタンを使って、変わるものだけを入力しています(金額とか施設名とか)
Excelから貼り付けたい時 ・各担当者が入力したデータを貼り付ける場合、元のExcelには支払方法・該当月がないので、 accessのコピー元に入れてコピーするか、またはExcelの方に追加してから貼り付けています。
・そのほか、光熱費やネットでの購入品などはcsvでダウンロードしたものを、支払日・支払い方法・該当月はこちらでコピー元に入れてコピーし、金額はcsvから貼り付け、施設名は別の施設名一覧Excelから貼り付け、等にしています。
このような感じで、元のレコードを複写しておいて、ところどころを貼り付けたいのです。
施設名 支払方法 該当月 だけを入力したレコードを、貼り付け用に100行用意する(=100回ボタンを押す)をしているので、それが10回押せば100行用意出来たら、すごく楽だなぁ、と思ったのです。
そういうことですね。ExcelとACCESS(データベース)はデータの持ち方が違うので、互いにデータをやり取りする場合は、データの形式を合わせるという作業が発生します
上記では「新規レコードを追加」で例にしましたが、テーブル上の操作では、既存レコードの見た目上2x2マスに、Excel上の2x2からコピーペーストもできますよ
ACCESS上の操作としてコピーペーストはできるとしましたが、問題の本質は、ACCESSで扱うために新たなデータを作りたいということでしょう
もう少し具体的には「新たなデータを作りたい」=「任意のレコード追加をしたい」ですね
さらに条件を挙げていくと、 「任意のレコード」=複数一括追加もしたい 「ID」->オートナンバーで取得 「日付と項目等」->既存レコードの複製=レコード追加前に一括で指定(準備) 「金額と備考欄等」->Excel上のデータ
と、現在手作業で行っていることをシステム(ExcelやAccess)に合わせて論理的に説明できるようになれば、あとはそれをシステム化するだけです(「Excel上のデータをどう指定するか」はもっと事細かに考える必要があります)
先にも上げましたが、データの形式を合わせるの部分をどれだけ正確に説明できるか?が問題です。具体的なシステム化部分はこの掲示板で多分それほど難しくない内容で回答が付くと思います
1行コピーして10行または20行複製
この前後も含めて理解に困るところですが、「10行コピーして10行」「20行コピーして20行」ではないんですかね?
1行が10行になるということは何十行ものExcelデータが何百何千のAccessデータになっているんでしょうか?
ありがとうございます。簡単ではないのですね。 Excelで作られたものが全く同じ形式ではないのと、オートナンバーの関係もあって、 例えば日付と項目等をレコード複製しておいて、金額と備考欄等をExcelから貼り付け、というふうにしています。 頻繁ではないですが、百回以上複製ボタンを押すことがあるので、まとめて出来たらなぁ~という淡い期待でした💦
いろいろ複雑な要件が絡む問題ですが、
普通にExcelで複数行コピーしたものを、ACCESSのテーブルでレコードを選択状態(左端のレコードセレクタ部分をクリック)にして張り付ければ新規レコードの追加として全て張り付きますよ
hiroton様 返信遅くなりまして申し訳ございません。
Accessのテーブルやクエリのデータを貼り付ける場合は下記で、Markdown書式のテーブルに変換して貼り付けてください。
Markdown Tables generator
なるほど・・・そういうことですね。
確かにそうすれば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という選択が間違いなのかもしれませんよ
何度もありがとうございます。
とりあえず、10行複製のボタンは簡単には出来ないんだなぁ、という事がわかりました。
規定値設定ですが、1月の伝票が150行続く時もあれば、その次には2月のもの、等バラバラなので、なかなか…という感じです。
正規化については、時間を見つけて取り組んでみたいと思います。
ありがとうございました。
この辺から推測するに、
支払伝票的なものをAccessで管理したいという印象。
だとすると、扱うデータは、
共通するデータ(ヘッダー項目)とレコード毎に変化するデータ(明細データ)に分けられると思います。
データベースは同じデータを繰り返し格納しないという設計原則があります。
繰り返されるデータ(今回ならヘッダー項目)と変化するデータ(今回なら明細データ)は別テーブルにすることになります。
このような設計を「正規化」といいます。いちど「正規化」でWEB検索してみてください。
例えば、Accessで解説しているページとしては下記あたりを参考に。
正規化とは - もう一度学ぶMS-Access
アクセスデータベース設計の基本(正規化) | ExcelとAccessの学習室
正規化されたテーブルなら同じデータを複製する必要はなくなります。
また、Accessでは正規化されたデータを入力する場合は、メイン/サブフォーム形式の入力フォームを使うのが一般的です。
メインフォームでヘッダー項目を入力、サブフォームで明細データを入力というUIになります。
Accessのフォームのメイン/サブフォームとは | できるネット
パターンが多すぎるようなら、中間作業をExcelでやってしまえばいいんじゃないかと思ってしまいますね。1行コピーして100行選択して貼り付けで100行分データが出来上がりです
Accessでレコードを選択してコピーからExcelに貼り付けで1行の元データも作成できますし
パターンが網羅できるようなら、すべての手作業パターンをそっくりそのままコード化してしまえば良いでしょう
"DefaultValue/既定値" プロパティ
新規レコードで、各フィールドごとに初期値を設定しておくことができます。わざわざレコードを複製しなくても、単純な入力作業が必要なところだけの入力で済みます
例えば、入力フォームに「規定値設定」ボタンを配置し、以下プロパティを設定します
[イベント プロシージャ]を設定した欄の右端の[...]をクリックするとVBEが立ち上がります
次のような表記になっているので、コードを記述します
↓
一度フォームを閉じて保存したあと、再度フォームを開いて「規定値設定」ボタンを押してみてください。新規レコードの「支払日」「支払種別」が、「規定値設定」ボタンを押したレコードの内容になります
accessの項目は以下です。
ID →オートナンバー
支払日 →複製したい場合とExcelから張り付ける場合がある
支払種別 →複製したい場合とExcelから張り付ける場合がある
支払先名 →複製したい場合とExcelから張り付ける場合がある
部門名 →空白でok
施設名 →複製したい場合とExcelから張り付ける場合がある
金額 →Excelから貼り付け
支払方法 →複製
該当月 →複製したい場合とExcelから張り付ける場合がある
備考 複製したい場合とExcelから張り付ける場合がある
・ひとつひとつ入力していく場合
このいくつかの項目の内容が同じ場合は、1行複写するボタンを使って、変わるものだけを入力しています(金額とか施設名とか)
Excelから貼り付けたい時
・各担当者が入力したデータを貼り付ける場合、元のExcelには支払方法・該当月がないので、
accessのコピー元に入れてコピーするか、またはExcelの方に追加してから貼り付けています。
・そのほか、光熱費やネットでの購入品などはcsvでダウンロードしたものを、支払日・支払い方法・該当月はこちらでコピー元に入れてコピーし、金額はcsvから貼り付け、施設名は別の施設名一覧Excelから貼り付け、等にしています。
このような感じで、元のレコードを複写しておいて、ところどころを貼り付けたいのです。
施設名 支払方法 該当月 だけを入力したレコードを、貼り付け用に100行用意する(=100回ボタンを押す)をしているので、それが10回押せば100行用意出来たら、すごく楽だなぁ、と思ったのです。
そういうことですね。ExcelとACCESS(データベース)はデータの持ち方が違うので、互いにデータをやり取りする場合は、データの形式を合わせるという作業が発生します
上記では「新規レコードを追加」で例にしましたが、テーブル上の操作では、既存レコードの見た目上2x2マスに、Excel上の2x2からコピーペーストもできますよ
ACCESS上の操作としてコピーペーストはできるとしましたが、問題の本質は、ACCESSで扱うために新たなデータを作りたいということでしょう
もう少し具体的には「新たなデータを作りたい」=「任意のレコード追加をしたい」ですね
さらに条件を挙げていくと、
「任意のレコード」=複数一括追加もしたい
「ID」->オートナンバーで取得
「日付と項目等」->既存レコードの複製=レコード追加前に一括で指定(準備)
「金額と備考欄等」->Excel上のデータ
と、現在手作業で行っていることをシステム(ExcelやAccess)に合わせて論理的に説明できるようになれば、あとはそれをシステム化するだけです(「Excel上のデータをどう指定するか」はもっと事細かに考える必要があります)
先にも上げましたが、データの形式を合わせるの部分をどれだけ正確に説明できるか?が問題です。具体的なシステム化部分はこの掲示板で多分それほど難しくない内容で回答が付くと思います
この前後も含めて理解に困るところですが、「10行コピーして10行」「20行コピーして20行」ではないんですかね?
1行が10行になるということは何十行ものExcelデータが何百何千のAccessデータになっているんでしょうか?
ありがとうございます。簡単ではないのですね。
Excelで作られたものが全く同じ形式ではないのと、オートナンバーの関係もあって、
例えば日付と項目等をレコード複製しておいて、金額と備考欄等をExcelから貼り付け、というふうにしています。
頻繁ではないですが、百回以上複製ボタンを押すことがあるので、まとめて出来たらなぁ~という淡い期待でした💦
いろいろ複雑な要件が絡む問題ですが、
普通にExcelで複数行コピーしたものを、ACCESSのテーブルでレコードを選択状態(左端のレコードセレクタ部分をクリック)にして張り付ければ新規レコードの追加として全て張り付きますよ
hiroton様
返信遅くなりまして申し訳ございません。