• 締切済み

エクセルVBAの処理速度アップについて

以下のエクセルVBAを組んでいるのですが、処理の速度をあげたいです。 無駄な記述があると思うのですが、調べても試行錯誤しても、上手くいきません。 処理速度をあげる記述をご教示願います。よろしくお願い申し上げます。 ※別ファイルのAccessファイルをデータベースとして、「今年」テーブルと、「前年」テーブルそれぞれから条件抽出して、受注数量を合計させるものです。 ※SQLのVBAです。なお、実際ファイルのVBAは、以下記述の5倍量あります(内容は、セル範囲が違うだけで同じ。現在速度:約30秒)。 ※「配列」というのを活用すれば速くなるようなのですが、理解できませんでした。。。 ーーーー【以下、VBA】----------- Sub DSUM集計() Application.ScreenUpdating = False Dim db As ADODB.Connection Dim rs As ADODB.Recordset Dim mySQL As String Dim cmd As ADODB.Command Dim AA As Variant AA = "AND 営業箇所" & Range("C13") & " AND 拒 IS NULL AND 販売伝票 <" & Range("D13") & " AND 品名 " & Range("E13") & " AND 得意先名 " & Range("F13") & " AND 請求先名 " & Range("G13") & " AND 出荷先名 " & Range("H13") Set db = New ADODB.Connection db.Provider = "Microsoft.Ace.OLEDB.12.0" db.Open "\\▲▲▲\ACCESS.accdb" With Worksheets("補助計算") mySQL = " SELECT SUM(受注数量) FROM 今年 " mySQL = mySQL & "WHERE 納入期日=" & Range("B13") & AA Set rs = New ADODB.Recordset Set cmd = New ADODB.Command Set cmd.ActiveConnection = db cmd.CommandText = mySQL Set rs = cmd.Execute Range("I13").CopyFromRecordset rs mySQL = " SELECT SUM(受注数量) FROM 今年 " mySQL = mySQL & "WHERE 納入期日=" & Range("B14") & AA Set rs = New ADODB.Recordset Set cmd = New ADODB.Command Set cmd.ActiveConnection = db cmd.CommandText = mySQL Set rs = cmd.Execute Range("I14").CopyFromRecordset rs mySQL = " SELECT SUM(受注数量) FROM 前年 " mySQL = mySQL & "WHERE 納入期日=" & Range("K14") & AA Set rs = New ADODB.Recordset Set cmd = New ADODB.Command Set cmd.ActiveConnection = db cmd.CommandText = mySQL Set rs = cmd.Execute Range("M14").CopyFromRecordset rs    mySQL = " SELECT SUM(受注数量) FROM 前年 " mySQL = mySQL & "WHERE 納入期日=" & Range("K15") & AA Set rs = New ADODB.Recordset Set cmd = New ADODB.Command Set cmd.ActiveConnection = db cmd.CommandText = mySQL Set rs = cmd.Execute Range("M15").CopyFromRecordset rs rs.Close Set rs = Nothing Set db = Nothing Application.ScreenUpdating = True End With End Sub ーーーーーーーーーーーーーーーーーーーー 以上

みんなの回答

  • imogasi
  • ベストアンサー率27% (4737/17068)
回答No.5

自信ないですが、気になったもので、1意見として、言わせてください。 今年データー>シート1 去年データ->シート2 に (エクセルシートにデータを)インポートします。VBAで遣っても、10行以内のコードで、できるでしょう。 ーー これで、なにがしかのタイム(作業時間)をロスしますが、処理(下記Excelシートでの処理)が、辛抱できる範囲内なら、下記のこの案もあり得るのでは。 ーー 今ADOでやっているのは ・今年データシートと昨年データシートの2種類データに対し、検索し集計する すなわち ・--今年シート----|ーーー昨年シート 納入期日 B13 B14 K14 K15 ーーーーーーーーーーーーーーーーーーーーー 営業所  C13 販売伝票 D13 左に  左に 左に 左に 品名   E13 同じ  同じ 同じ 同じ 得意先  F13 請求先  G13 出荷先名 H13 が条件で、条件の内容を規定している。 すなわち(アクセスとは別の)シートのセルを参照して、データが条件と一致するか見る。 これはユーザーフォーム等で1セットの条件に、見やすいように、まとめられると思う。 他のソフトにまたがる処理でなくなるので完了処理が早くなると思う。 条件が1行内の複数列が、条件を満たしているかどうかを判別するタイプのもので、レコード間(エクセルの場合で言えば、違った行データ)の関連を気にする性格の検索ではないので幸い(簡単)なわけです。 ーー 一方、エクセルのVBAコード Sub test03() c = Worksheets("Sheet1").Range("a1:j10000") s = 0 For i = 1 To 10000 If Cells(i, 1) = "a9973" Then s = s + Cells(i, "K") ’"a9973"は私のデータの場合の勝手な内容 If Cells(i, 1) = "a9978" Then s = s + Cells(i, "K") Next i MsgBox s End Sub (10列X10000行の仮のデータで実行してみた) のような処理が可能になるので、質問のAAの部分にある条件をエクセルVBAコードで 組めば簡単ではないかな。この際、ごく初歩的な、総なめ法を使うのです。 これは http://officetanaka.net/excel/vba/speed/s11.htm のような記事があったのが、頭にあったからです c = Worksheets("Sheet1").Range("a1:j10000")の1行で10X10000のセルデータが2次元配列的になってくれる。 cはVariant変数で、質問の「>配列」というのを活用すれば速くなるようなのですが」から思いついたのですが。 会社でVBAを組むことは許されているようですし。 VBAコードでなく、SUMIFS関数でできるかもしれない。 http://www.becoolusers.com/excel/sumifs.html ーーー ・データ量(数、100万を超えるのでしょうか?)が質問に書いてない ・SQL文のAAの部分で、「営業箇所」などのあとに=が必要ないですか。 ・小生も自信を持って本件書いてない。おかしければ無視してください。 ・エクセルVBAの(SQLをつかわない)プログラムを作りなおすのは、面倒ですが  総当たり法のロジックでやるなら簡単なプログラム(IF文でAND条件)でしょう。 ・なぜエクセルシートに条件を入れているのか。アクセスのフォームなどに、まとめるのが普通では。 迷いや疑問はあるのですが。

kscgakuin
質問者

お礼

ご回答ありがとうございます。遅くなりすみません。 ご教示いただきました内容で確認してみます。ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
回答No.4

どこで時間がかかているのかを Debug.Print "1:" & Cstr(Timer) Debug.Print "2:" & Cstr(Timer) Debug.Print "3:" & Cstr(Timer) を要所要所にいれて処理時間を確認してください。 見たところSQL文の実行以外は、瞬時に終わる命令ばかりです。 つまりデータの取得が遅い=テーブル構造がまずい(適切にキーやインデックスが設定されていない?)と、思われます。 もしキーやインデックスが設定されているのに遅い場合は、Accessの限界と諦めるしかありません。

kscgakuin
質問者

お礼

ご回答ありがとうございます。遅くなりすみません。 わかりました。試してみて確認してみます。ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
回答No.3

今、対象とされているテーブルとテーブル構造が同じテーブルをコピペで作ります。 仮にテーブル名を抽出ベースとします。 Sub DSUM集計() Application.ScreenUpdating = False Dim db As ADODB.Connection Dim rs As ADODB.Recordset Dim mySQL As String Dim cmd As ADODB.Command Dim AA As Variant AA = " 営業箇所" & Range("C13") & " AND 拒 IS NULL AND 販売伝票 <" & Range("D13") & " AND 品名 " & Range("E13") & " AND 得意先名 " & Range("F13") & " AND 請求先名 " & Range("G13") & " AND 出荷先名 " & Range("H13") & ";" Set db = New ADODB.Connection With db   .Provider = "Microsoft.ACE.OLEDB.12.0;"   .Properties("Data Source").Value = "\\▲▲▲\ACCESS.accdb"   .Open End With mySQL = "DELETE * FROM 抽出ベース" CN.Execute mySQL '既存レコード削除 mySQL = "INSERT INTO 抽出ベース" & _       " SELECT * FROM 元テーブル名" & _       " WHERE " & AA CN.Execute mySQL '抽出ベーステーブルへのレコード更新 ’とすれば以下 With Worksheets("補助計算") mySQL = " SELECT SUM(受注数量) FROM 抽出ベース " mySQL = mySQL & "WHERE 納入期日=" & Range("B13") ' & AA ・・・省略 となるのでAAの抽出コストが無くなりますから 少しは速くなるのかな・・・と考えた次第です。 抽出ベーステーブルの更新に時間が掛かり効果が無いかもしれませんが、 サンプルを作るわけにもいかないので当方では検証不可です。 ただ実際には5倍の処理 シートへの書き込み=4×5=20回くらい? ごく大雑把に30秒÷20=1.5秒なので対策しても微々たる効果しかないかもしれません。 ネットワーク経由など環境に依存する部分もあるので…。

kscgakuin
質問者

お礼

ご回答ありがとうございます。遅くなりすみません。 ご教示いただきましたvbaをいちど試してみます。ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
回答No.2

まだやってなくて、やれるのであれば・・・ 各テーブルの「納入期日」にインデックス(重複あり)を追加でどうだろうか?

kscgakuin
質問者

お礼

ご回答ありがとうございます。遅くなりすみません。 インデックス設定やってみます。ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
回答No.1

抽出のベースとなる > AA = "AND 営業箇所" & Range("C13") & " AND 拒 IS NULL AND 販売伝票 <" & Range("D13") & " AND 品名 " & Range("E13") & " AND 得意先名 " & Range("F13") & " AND 請求先名 " & Range("G13") & " AND 出荷先名 " & Range("H13") でテーブルを作成するわけには行かないのでしょうか。 (Accessファイルの作成者(貴方ではない?)が自身以外は不可侵・参照のみ許可だとダメですが…) あと、 Set rs = New ADODB.Recordset Set cmd = New ADODB.Command Set cmd.ActiveConnection = db が繰り返し出てきますが最初だけで充分だと思います。 とりあえず。

kscgakuin
質問者

お礼

ご回答ありがとうございます。抽出のベースとなる部分のテーブル化についてですが、おっしゃっている意味は「その部分の条件内容が固定ならば、テーブルにしたら良いのでは?」ということでしょうか?(間違っていたらすみませんなのですが)そういう意味でのテーブル化は、希望内容に残念ながら沿いません。 私の言葉足らずで申し訳ございませんでしたが、抽出のベースとなる部分はエクセル側で条件を適宜変更するという運用想定をしているためです。。。 繰り返しの部分につきましては、試してみます。ありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • EXCEL vbaからACCESSのクエリを開く

    EXCEL2010 WEBを参照してEXCEL VBAでACCESSのクエリを開くマクロを流用しました。 下記がマクロの内容です。 Private Sub Import() Dim db As ADODB.Connection Dim rs As ADODB.Recordset 'ACCDBファイルに接続します Set db = New ADODB.Connection db.Provider = "Microsoft.Ace.OLEDB.12.0" db.Open "C:\work\TEHAI.accdb" 'レコードセットを開きます Set rs = New ADODB.Recordset 'Accessのクエリを開く rs.Open Source:="TEHAI", ActiveConnection:=db If rs.EOF Then MsgBox "抽出した結果、レコードが見つかりません。" Else ' レコードをシートへ貼り付ける Range("A1").CopyFromRecordset rs End If rs.Close Set rs = Nothing Set db = Nothing End Sub これを実行すると、 抽出した結果、レコードが見つかりません。 が表示されます。 ACCESS単体でTEHAIクエリを実行したら、約3万件くらいヒットします。 EXCELマクロから実行したらACCESSからデータをもってこられません。 なぜレコードが見つかりません、 となるのでしょうか? マクロのどこがおかしいのか、教えていただきたく。 ちなみに、もともとの内容から変更したのは db.Open "C:\work\TEHAI.accdb" rs.Open Source:="TEHAI", の2ヶ所だけです。

  • Commandオブジェクトについて

    VBをやった事の無い私が、会社でプログラムを組むことになってしまい、今、困っています。 ADOを使ってSQLに接続する場合、RecordsetやConnection、Commandなどのオブジェクトがありますよね? 会社で渡されたサンプルには、 /////////////////////////////////////////////// Dim rc As New ADODB.Recordset Dim cmd As New ADODB.Command  ・  ・  ・ cmd.ActiveConnection = a_db cmd.CommandText = "SELECT * FROM AA_DATA" rc.Open cmd  ・  ・  ・ /////////////////////////////////////////////// ↑こんな感じにCommandオブジェクトを使用しているのですが、参考書などのサンプルを見ると、Commandオブジェクトをあまり使っていないように思えます。 私は、Commandオブジェクトを使用しなくても接続できると解釈したのですが・・・。 何故Commandオブジェクトを使用するのでしょうか? Commandオブジェクトを使用することによって、何かメリットがあるのでしょうか? 本当に初心者質問で申し訳ありません。 MSDNのヘルプや参考書を見てもわからないんです。 どなたか分かりやすく教えてください。 よろしくお願いいたします!

  • CMD.Executeの結果をメッセージボックスで表示したい

    Public Sub SQLActionCmd()     Dim CN As ADODB.Connection     Dim CMD As ADODB.Command     Dim MYSQL As String     '接続     Set CN = CurrentProject.Connection     '更新     MYSQL = "SELECT * FROM 名簿 WEHRE 性別 = "男" ;"     Set CMD = New ADODB.Command     CMD.ActiveConnection = CN     CMD.CommandText = MYSQL     CMD.Execute    '終了     Set CMD = Nothing     RS.Close: Set RS = Nothing     CN.Close: Set CN = Nothing    End Sub と言う感じで実際にはAccessのフォームのボタンをクリックしたタイミングでコードをかいているのですが、このCMD.EXECUTEを実行した結果、テーブルに該当データがなければない旨のメッセージボックスを出したいのです。 そういうことは可能でしょうか?

  • ACCESS2010でSELECTの問題

    ACCESS初心者です。 既にレコードが存在すテーブルで、DBを更新モードで開き、SELECT句を実行すると、更新モードから読み込みモードになり、更新/追加ができなく困っています。 以下にサンプルコーディングを掲載します。 SQLを実行する前と、実行後に  LockType を表示したところ、  実行前は「3」更新可  実行後は「1」更新不可 となります。 どのようにすれば「LockType」が変らないようにできるでしょうか。 よろしくお願いします。 ---------------------------------------------------------------------------------------------------------------------- Dim cmd As New ADODB.Command Dim rs_issues As ADODB.Recordset Dim adoCn As Object 'ADOコネクションオブジェクト Set adoCn = CreateObject("ADODB.Connection") 'ADOコネクションオブジェクト adoCn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & "データベース名" Set cmd = New ADODB.Command Set cmd.ActiveConnection = adoCn Set rs_issues = New ADODB.Recordset rs_issues.Open "T_issues", db, adOpenDynamic, adLockOptimistic cmd.CommandText = "SELECT *FROM T_issues WHERE i_チケット番号=123456"   Debug.Print rs_issues.LockType   '(1)LockType=3 Set rs_issues = cmd.Execute Debug.Print rs_issues.LockType   '(1)LockType=1

  • VB6.0でエクセルを扱うプログラムについて

    こんにちは。VB初級者です。宜しくお願いします。 現在、VB6.0でエクセルの表を操作するようなプログラムを作っています。下に書いたプログラム(わかりにくいとは思いますが、ご教授お願いします。)で値の更新は出来たようなのですが、実際に表を開こうとすると”不正な処理が行われました”というエラーメッセージが出て開くことが出来ません。ADOオブジェクトでエクセルを扱うのがちょっとおかしい(?)のかもしれませんが、今回はEXCELオブジェクトは使わないという方針です。 自分ではどこが間違っているかわかりませんでしたので教えて頂ければと思います。宜しくお願い致します。 Private Sub Command1_Click() Dim cn As ADODB.Connection Set cn = New ADODB.Connection cn.Provider = "Microsoft.Jet.OLEDB.4.0" cn.Properties("Extended Properties") = "Excel 8.0" cn.Properties("Data Source") = "C:\VB\株価管理\株価.xls" cn.Open Dim cmd As ADODB.Command Dim mySQL As String mySQL = "update [株価$] set 高値 =10000 where 高値 = 7" Set cmd = New ADODB.Command cmd.ActiveConnection = cn cmd.CommandText = mySQL cmd.Execute Set rst = New ADODB.Recordset rst.Source = "Select * From [株価$]" rst.ActiveConnection = cn rst.CursorType = adOpenDynamic rst.Open , , , , adCmdText Do While Not rst.EOF Debug.Print rst.Fields("高値") rst.MoveNext Loop rst.Close cn.Close Set rst = Nothing Set cn = Nothing Set cmd = Nothing End Sub

  • レコードの削除

    VB6.0 ACCESSで開発しています。 t_nyukoテーブルのデータを全て削除するのは下記のように 出来たのですが dataGridに表示されているものを1つ選択し 選択されたものだけ削除したいのですがどうすればいいのでしょうか? よろしくお願いします。 Private Sub Command1_Click() Dim cn As New ADODB.Connection Dim cmd As ADODB.Command Dim cat As New ADODB.Command Dim strSQL As String   Set cn = New ADODB.Connection cn.ConnectionString = _ "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=C:\temp\db2.mdb" cn.Open cat.ActiveConnection = cn strSQL = "DELETE FROM t_nyuko " Set cmd = New ADODB.Command cmd.ActiveConnection = cn cmd.CommandText = strSQL cmd.Execute cn.Close Set cmd = Nothing Set cn = Nothing Set cat = Nothing End Sub

  • セレクトしたデータを更新させるにはどうしたらよろしいのでしょうか?

    更新されません。 セレクトしたデータをそのまま更新させようとしているからいけないのでしょうか? <% Dim DB,Rs,Cmd Set DB = Server.createobject("ADODB.Connection") On error Resume Next DB.open "mysql" DB.BeginTrans Set Cmd=Server.createobject("ADODB.command") Cmd.activeconnection=db Cmd.commandtext="select * from stb where id =1" Set Rs = Cmd.Execute i=cint(1) j="ADSL" Do until Rs.eof Rs("id"),value= i Rs("name").value= j Rs.update If DB.Errors.Count >0 then DB.Rollbacktrans response.write "エラー" for idx = 0 to 2 Response.write db.errors(idx).Description & "<br>" next else DB.commitTrans response.write "データが登録されました。" end if Rs.movenext Loop Rs.close DB.close set Cmd = Nothing set Rs = Nothing set db = Nothing %>

  • ストアドプロシージャの実行で...

    Test_Pro、というストアドプロシージャを実行させたいんですが、 Microsoft OLE DB Provider for SQL Server エラー '80040e14' ストアド プロシージャ 'Test_Pro' が見つかりませんでした。 というエラーが出てしまいます。どうして??? 実行させる為に書いたソースは、 set cmd = Server.CreateObject("ADODB.command") Set cmd.ActiveConnection = conn cmd.CommandText = "Test_Pro" cmd.CommandType = 4 Set rs = cmd.Execute("@a", a) です。

  • ExcelVBA Accessにデータ書き込み

    VBAでコマンドボタンを押した際に特定のセルの値をAccessDBに入力するプログラムを作りたいのですが、上手くいきません...。 実行した際に「実行時エラー '21472179000 (80040e 14)': オートメーションエラーです。」と表示されます。 また、ステップインで実行してみるとEnd Withのところでエラーが発生します。 恐らくインサート文が間違っていると思うのですが、試行錯誤しても解決できませんでしたので教えて頂きたいです。 以下プログラムです。 Private Sub CommandButton1_Click() Dim cn As ADODB.Connection Dim cmd As ADODB.Command Dim rs As ADODB.Recordset Dim constr As String Dim strSQL1 As String Dim a As String a = Range("A1").Value Dim b As String b = Range("A2").Value Dim c As String c = Range("A3").Value constr = "Provider=Microsoft.ACE.OLEDB.12.0;" & "Data Source=~.accdb strSQL1 = "insert into " & _ "TableName (1,2,3) " & _ "values ('" + Range("A1").Value + "','" + Range("A2").Value + "','" + Range("A3").Value + "')" Set cn = New ADODB.Connection cn.ConnectionString = constr cn.Open Set cmd = New ADODB.Command With cmd .ActiveConnection = cn .CommandText = strSQL1 .Execute End With Set cmd = Nothing Set rs = Nothing cn.Close Set cn = Nothing End Sub 以上、宜しくお願い致します。

  • 二つのMDBファイルの間のデータのやり取り

    おせわになります。みなさんの知恵を貸してください。 いかがシステム構成です。 A.mdb(テーブル:Work1) B.mdb(テーブル:Work2) A.mdbはカレントデータベースです。B.mdbはDSN=KANRIで アクセスしたいです。 現在Work1のデータをWork2に追加したいのですが、どのような方法が考えられますか? ちなみに以下のコードを書いてみました。 -------------------------------------------------- Dim cn1 As New ADODB.Connection, cn2 As New ADODB.Connection Dim rs1 As New ADODB.Recordset, rs2 As New ADODB.Connection Dim com As New ADODB.Command, mysql As String Set cn1 = CurrentProject.Connection cn2.ConnectionString = "provider=MSDASQL;DSN=KANRI" mysql = "insert into Work2 select * from Work1" com.activeconnection = cn2 com.commandtext = mysql com.Execute Set com = Nothing rs1.Close: Set rs1 = Nothing rs2.Close: Set rs2 = Nothing cn1.Close: Set cn1 = Nothing cn2.Close: Set ch2 = Nothing -------------------------------------------------- Work1は見当たらないとエラーが出ました。 どなたか教えてください。 rs1.EoF Loop をまわしながら一行ずつ追加するしかないでしょうか?

このQ&Aのポイント
  • インクを純正に交換してもインク交換を要求され、交換したのボタンが反応しない
  • 使用環境はWindows10で無線LAN接続
  • 関連するソフト・アプリや電話回線の種類は不明
回答を見る

専門家に質問してみよう