• 締切済み

[Excel ADO] WITH句の可否

Excel2007のADOを使ってCSVファイルのデータを集計する方法を習得中です http://okwave.jp/qa/q9081610.htmlで質問させていただきました内容で、 uriage.csv 伝票日付,伝票番号,取引先名,明細番号,納入先コード,商品名,単位,数量,単価,金額,取引区分 270901,00000664,X社,1,0071,商品A,個,4,2250,9000,1 270901,00000664,X社,2,0071,商品B,個,4,1750,7000,1 270901,00000664,X社,3,0071,消費税,,0,0,1280,2 270903,00000739,X社,1,0067,商品C,式,1,0,0,1 270903,00000739,X社,2,0067,商品D,個,1,0,0,1 270915,00000360,X社,1,,振込,,0,0,4320,0 270915,00000363,X社,1,,振込,,0,0,78840,0 270915,00000363,X社,2,,振込,,0,0,135540,0 271022,00000831,Y社,1,0090,商品B,式,1,10000,10000,1 271022,00000831,Y社,2,0090,消費税,,0,0,800,2 271022,00000832,Y社,1,0144,商品D,個,1,2000,2000,1 271022,00000832,Y社,2,0144,消費税,,0,0,160,2 271105,00000447,Y社,1,,振込,,0,0,2160,0 271110,00000459,Y社,1,,振込,,0,0,10800,0 nonyu.csv 納入先コード,納入先名 0067,本社 0071,M支店 0084,N支店 0090,本社 0109,S支店 0144,T支店 というテーブルに対して、以下のようなSQLを発行することで、VBAによらずSQLのみで処理することができるようになりました(実際はもう少し複雑なSQLですが、質問に際して簡略化しました) Sub sqltest() Dim cn As ADODB.Connection Dim rs As Recordset Set cn = New ADODB.Connection cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & ActiveWorkbook.Path & ";" & _ "Extended Properties='Text;HDR=YES'" cn.CursorLocation = adUseClient Sql = "SELECT * FROM ( " Sql = Sql & "SELECT 明細番号,伝票日付,伝票番号,商品名,単位,数量,単価,IIF(取引区分>0,金額),NULL,IIF(取引区分=0,金額) FROM uriage.csv 売上" Sql = Sql & " UNION ALL " & _ "SELECT 0,伝票日付,伝票番号,取引先名,NULL,NULL,NULL,NULL,NULL,NULL FROM uriage.csv 売上" & _ " GROUP BY 取引先名,伝票日付,伝票番号" Sql = Sql & " UNION ALL " & _ "SELECT 99,伝票日付,伝票番号,'納入先: ' & 納入先名,NULL,NULL,NULL,NULL,SUM(金額),NULL FROM uriage.csv 売上" & _ " LEFT JOIN nonyu.csv AS 納入先台帳 ON 売上.納入先コード=納入先台帳.納入先コード" & _ " WHERE NOT ISNULL(売上.納入先コード) " & _ " GROUP BY 取引先名,伝票日付,伝票番号,納入先名" Sql = Sql & ") ORDER BY 伝票日付,伝票番号,明細番号" Set rs = cn.Execute(Sql) Range("A2").CopyFromRecordset rs End Sub 一応できたことはできたのですが、データが大量になってくるとSELECT文を3回発行しているためかレスポンスが非常に悪くなってしまっています(上記では、全データを対象にしていますが、実際はWHEREにより日付、取引先名、納入先名などで絞り込んでいます。これを3回やるのは目に見えて無駄とは思うのです) 高速化の方策をいろいろ検索してみましたところ、UNIONで繋げるのは愚策で、共通するSQL文をWITH句でまとめるのが良いという記事がありました しかし、WITHを使おうとしてもエラーとなってしまいます。Excel ADOでは使えないのでしょうか? あるいは、まったく異なるアプローチなど、何かありましたらご示唆ください。 よろしくお願いします

みんなの回答

  • ushi2015
  • ベストアンサー率51% (241/468)
回答No.5

こんにちは IIFを使った方が速かったですか。 提示されたデータ量だけだとWHERE分けた方が速かったのですが、ダメですね。 あと、ORDER BY は元々UNION後でした済みません。 for文で回しているのはシートの1行目にフィールド名セットしていだけです。 コメントアウトしておいて下さい。

  • ushi2015
  • ベストアンサー率51% (241/468)
回答No.4

こんにちは、間違えました。 UNION後にしたのはWHEREじゃなくてSORTです。(ORDER BY)

hzd00430
質問者

お礼

すみません、これはどういう意味でしょうか? 元々のコードでも、UNION後にORDER BYをかけていたのですが。 ちなみに、for文で回している Cells(1, i) = Replace(rs.Fields(i - 1).Name, "'", "") は何をやっているのでしょうか?

  • ushi2015
  • ベストアンサー率51% (241/468)
回答No.3

こんにちは、No2です Oracleは持っていないですし、OraOLEDB.OracleでCSVファイルが扱えるのかも 分からないので、SQL文で・・・ UNIONするデータのフィールドでIIFで演算するのはやめてみて、 気休めでUNION後のWHEREにしてみると、 Sub sqltest_a_2()   Dim cn As ADODB.Connection   Dim rs As ADODB.Recordset   Dim Sql As String   Dim i As Long   Dim ss As Single      Range("A1").CurrentRegion.ClearContents      ss = Timer      Set cn = New ADODB.Connection   cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _     "Data Source=" & ActiveWorkbook.Path & ";" & _     "Extended Properties='Text;HDR=YES'"        cn.CursorLocation = adUseClient      Sql = "SELECT 明細番号,伝票日付,伝票番号,摘要,単位,数量,単価,合計,納入先伝票計,振込計 FROM ( "   Sql = Sql & "SELECT 明細番号,伝票日付,伝票番号,商品名 AS 摘要,単位,数量,単価,金額 AS 合計,NULL AS 納入先伝票計,0 AS 振込計 FROM uriage.csv WHERE 取引区分>0 "   Sql = Sql & " UNION ALL "   Sql = Sql & "SELECT 明細番号,伝票日付,伝票番号,商品名,単位,数量,単価,NULL,NULL,金額 FROM uriage.csv WHERE 取引区分=0 "   Sql = Sql & " UNION ALL "   Sql = Sql & "SELECT 0,伝票日付,伝票番号,取引先名,NULL,NULL,NULL,NULL,NULL,NULL FROM uriage.csv "   Sql = Sql & "GROUP BY 取引先名, 伝票日付, 伝票番号 "   Sql = Sql & " UNION ALL "   Sql = Sql & "SELECT 99,伝票日付,伝票番号,'納入先: ' & 納入先名,NULL,NULL,NULL,NULL,SUM(金額),NULL FROM uriage.csv 売上 "   Sql = Sql & "LEFT JOIN nonyu.csv AS 納入先台帳 ON 売上.納入先コード=納入先台帳.納入先コード "   Sql = Sql & "WHERE NOT ISNULL(売上.納入先コード) "   Sql = Sql & "GROUP BY 取引先名,伝票日付,伝票番号,納入先名 "   Sql = Sql & ") ORDER BY 伝票日付,伝票番号,明細番号"   Set rs = cn.Execute(Sql)   For i = 1 To rs.Fields.Count     Cells(1, i) = Replace(rs.Fields(i - 1).Name, "'", "")   Next   Range("A2").CopyFromRecordset rs   Debug.Print Timer - ss End Sub 多少は速くなりますか?

hzd00430
質問者

お礼

コメントありがとうございます rs.RecordCountが10万ほどのデータを対象に試してみたところ、 IIFを使った場合が、6.953125 WHEREを使った場合が、8.3125 となりました。 やはりSELECT文を増やすのは負荷になるような気がします

  • ushi2015
  • ベストアンサー率51% (241/468)
回答No.2

こんにちは 何故、 VBAによらずSQLのみで処理すること に拘るのですか? UNION ALL で遅いのなら、個別にExcelシートに抽出してソートするとか、 VBAでMDBを作成してCSVファイルへのリンクテーブルを作成して予めクエリで 処理して取り込むとか、色々試して処理時間の比較してみてはどうですか?

hzd00430
質問者

お礼

コメントありがとうございます > VBAによらずSQLのみで処理することに拘るのですか? あえて言えば技術的興味でしょうか SQL処理のことを知ってまだ日が浅いですが、 手続き言語とは違う記述方法が新鮮で楽しいです このCSV処理は業務上必要なことではありますが、 それをSQL習得のための課題ととらえ、 敢えてSQLだけでやる方法を模索しています

回答No.1

プロバイダが"MSDAORA"だとWITH区は使えません。"OraOLEDB.Oracle"を使ってください。

hzd00430
質問者

お礼

コメントありがとうございます 当方、Oracleの環境は一切所持していないのですが フリーで入手可能なものはありますか? また、DBMSでなくCSVファイルに対して使用可能ですか? ざっと検索してみましたが、それらの情報が見つかりませんでした よろしければ教えてください

関連するQ&A

  • [Excel ADO]合計額の挿入は可能ですか?

    Excel2007のADOを使ってCSVファイルのデータを集計する方法を習得中です ある業務アプリからエクスポートしたデータなのですが、 売上伝票データ: 伝票日付、伝票番号、取引先名、明細番号、商品名、数量、単価、金額、取引区分、納入先コード 納入先コードテーブル: 納入先コード、納入先名 取引区分が0なら売上、1なら入金(入金伝票の場合納入先コードがNULL) これを集計して売上明細表をつくるとして、 伝票毎に伝票合計額、および納入先名を挿入するようなことが SQL文だけで可能でしょうか?

  • [Excel ADO]条件にマッチした伝票の出力

    Excel2007 ADOを使ってCSVのSQL処理をしています 対象は売上伝票で、取引先名、商品名などで検索をかけるのですが その結果がマッチした明細のみしか取り出せないのをなんとかしたいです 例えば、1つの伝票には複数明細が含まれるのが通常ですが、 商品名で検索すると、その商品の明細しか出てきません これを、マッチした明細を含む伝票全体を取り出したいのです SELECT 伝票日付,伝票番号 FROM T_売上 WHERE 取引先="A社’ AND 商品名='鉛筆' GROUP BY 伝票日付,伝票番号 こんな形で検索対象を含む伝票の伝票番号リストを得ることはできたので、 次はこの日付と番号でWHEREをかけるのか あるいはEXSISTSなどを使うのか ちょっと具体的にイメージできません 教えていただけるとありがたいです よろしくお願いします

  • [Excel ADO]ソートキー値の変更方法

    Excel2007を使って、ADOによるCSVデータの集計をしています 対象のデータで、行番号をキーにしてソートするのですが 0の場合のみ一番最後になるような方法はありますか? 素人考えでは、0の場合は999999など十分大きな値に強制的に書き換え、 それからORDER BY 行番号による並び替えができれば、などと妄想しています 参考までに、もう少し具体的に申し上げますと、売上データのフィールドが 伝票日付、伝票番号、明細番号(行番号)、、、と並んでおり 基本的にはこの順番でORDER BYをかければいいのですけど、 締時消費税のみ伝票番号が0、明細番号が0となっているのです(伝票日付は締日) 普通に処理すると締日の売上データが、締時消費税の下に来てしまうので避けたいです 何かいい方法がありましたら教えてください

  • 複数条件の設定について(EXCEL)

    EXCELで、次のような表を作成しています。 シート1               シート2 得意先名  商品名  納品日       A社 B社 C社  A社     X           X  B社     Z           Y  A社     X           Z  C社     Y シート2には、得意先&商品ごとに納品日が入力されたら件数がカウントされるように したいんです。今までの質問をヒントに、SUMPRODUCT関数やIF関数で SUMPRODUCT((得意先名="A社")*(商品名="X")*(納品日<>"")) IF(納品日<>"",SUMPRODUCT((得意先名="A社")*(商品名="X")),"") と作成してみたんですが、うまく行きません。 マクロはわからないんで、できればマクロを使わずに作成したいんですが、何か方法は ありますか?

  • アクセスVBA。ADO

    CSVから列を分割してテーブルにしたいかったので 下記のコードを記述しましたが、 Dim cn As ADODB.Connection Dim rs As New ADODB.Recordset Dim datacount As Long Set cn = New ADODB.Connection With cn .ConnectionString = "Provider=Microsoft.jet.OLEDB.4.0;Data Source=" & CurrentProject.Path & "\;" .Properties("Extended Properties").Value = "text;HDR=YES;" .Open End With Set rs = cn.Execute("SELECT * FROM 構成マスタ.csv") datacount = rs.Fields.Count For i = 0 To datacount strsql = "SELECT " & rs.Fields(i).Name & " INTO " & rs.Fields(i).Name & " FROM 構成マスタ.csv;" cn.Execute strsql Next i rs.Close cn.Close Set rs = Nothing Set cn = Nothing SQLを実行するところで、「日付エラー」となってしまいます。 データには特に日付等はないのでエラーになる原因がわかりません。 どなたかご教示いただけますでしょうか。

  • access2003

    2000種ほどの商品を扱っています。商品コードひとつにつき、仕入先・取引先が1箇所ずつ決まっていて、値段の変化もあまりありません。伝票を見ながら、フォームから直接売上入力を行い、請求処理と売上分析に利用したく思います。 ◆親)売上入力フォーム:売上管理番号/日付/取引先/取引先伝票番号/売上合計金額 ◆子)売上明細フォーム:商品コード/商品名/単価/数量/明細金額 ◆売上入力テーブル:売上管理番号/取引先/日付/取引先伝票番号 ◆売上明細テーブル:明細番号/売上管理番号/商品コード/数量/明細単価 入力の効率化を図るため、1部品1取引先であることを利用して、親フォームで取引先を選択することで商品を絞り込み、子フォームの商品選択コンボボックスにはその取引先の商品だけが表示させるようにしたいと思います。どのような方法が考えれるでしょうか? クエリを使うのだと思いますが、いろいろ試しても失敗してしまいます。 また、その上でさらなる絞込みとして、明細の各行で各商品を選択する際に、商品コードの一部を入れたり、仕入先名を入れると部品が絞り込めるようにできないでしょうか? アドバイス、参考資料、なんでもお寄せください! どうぞよろしくお願いいたします。

  • アクセスからテキストファイルにエクスポートしたい。

    お願いします。 会社の商品管理でアクセスを使用しています。 クエリで抽出したデータを、テーブルに保存したものを、取引先に添付データとして送らなくてはいけません。 取引先の指定が、固定長テキストファイルなのですが、幾つかわからないことがありますので教えてください。 (1)事務員に、あまり難しい事をさせたくないのでできるだけ自動化したい。 (2)項目は、伝票日付8桁、伝票番号8桁、商品コード5桁、数量10桁 (3)伝票日付は、現在テキスト型で、定型入力0000/00/00の形式です。  これをyyyymmddの8桁に直さなくてはいけません。 以上、よろしくお願いいたします。

  • access2003 抽出条件が持ち越されてしまう

    http://okwave.jp/qa3580875.html ↑にて質問させていただいた者です。  一部繰り返しになりますが、2000種ほどの商品を扱っています。伝票を見ながらフォームから直接売上入力を行いたく思います。 ◆親)売上入力フォーム:売上管理番号/日付/取引先/取引先伝票番号/売上合計金額 ◆子)売上明細フォーム:商品コード/商品名/単価/数量/明細金額 ◆売上入力テーブル:売上管理番号/取引先/日付/取引先伝票番号 ◆売上明細テーブル:明細番号/売上管理番号/商品コード/数量/明細単価 子フォームで商品コードのフィルターとして、 1)親フォームで選択した取引先の商品のみ→[Forms]![売上入力フォーム]![取引先]を導入 2)ワイルドカード「Like "*" & [商品コードの一部を入力] & "*"」 のふたつを使っていますが、うまく動作してくれません。 いったん商品コードを選択すると、明細の次の行に移動しても取引先選択のポップアップが出ず、コンボボックスには同じ選択肢が提示されます。さらに、新しいレコードに移動してもポップアップなし&同じ選択肢が続きます。 この状態を回避する方法を教えてください。 長くなりましたが、どうぞよろしくお願いします。

  • access2013 ルックアップの絞り込み

    初心者です。 access2013で、会社の作業伝票を作成したいとおもっています。 「作業伝票」テーブルの「取引先名」を、 「取引先」テーブルからルックアップで選択できるようにしたいのですが、 取引先すべてを表示すると多すぎます。 そこで、ふたつのテーブルに「業種」の項目をルックアップでつくり、 たとえば「作業伝票」テーブルの「業種」で「製造業」をえらんだときには、 「取引先名」のルックアップに、「取引先」テーブルの「業種が製造業」の項目だけ 表示されるようにできないでしょうか。 それとも、ほかに良いグループ分けの方法がありますか? ご回答、よろしくお願いします。

  • SQLで追加処理

    sqlで受注日を丁度ここでかかれている and 受注残.受注日 between '2008/08/29' and '2008/09/01' を別々に出したいのですが。 このように分けて追加したいんでですが、思うようにいかない 教えてください  下記のSQLは今作成中のものです。 お願いします 端末番号 受注番号 セット品受注番号 ・・・・・・受注日 受注日1 ----------------------------------------------------------------------------- 1 2312312 NULL 2008/08/29 2008/09/01 1 3423343 NULL 2008/08/29 2008/09/01 1 5435443 NULL 2008/08/29 2008/09/01 1 5435435 NULL 2008/08/29 2008/09/01 1 5435435 NULL 2008/08/29 2008/09/01 1 5453454 NULL 2008/08/29 2008/09/01 insert into 受注月報( 端末番号,受注番号, セット品受注番号,受注伝票区分, 得意先番号,納入先番号,受注日, 最終出荷日,品目番号, 品目名,形式,品目分類,注文番号,製番, 品目区分,売上担当者,出荷予定日, 出荷予定変更前日, 納期,受注数,単価単位, 単位番号,単位名,引当数, 単価,仮単価区分,金額,特記事項1, 特記事項2,出荷数, 完納区分,計画必要数, 計画立案済数,生産計画日, 地区番号,県番号,製造日程有無区分, 照会項目,登録日,更新日,消費税率, 通貨,通貨名,他社品番, 工場番号,引当在庫場所,納入先名, 郵便番号,住所1,住所2, 相手先担当者,電話番号,FAX番号, 輸送LT,図番,運送店, 相手販売店,得意先担当者名, 納入先担当者名,原価, 原価仮単価,営業価格, 営業価格仮単価,取引先略名,担当者番号, 担当者名,区分明細名, 区分明細名1,区分明細名2,取引先略名1,取引先名称) select '1', 受注残.*, 取引先.取引先略名, 担当者.担当者番号, 担当者.担当者名, 区分明細.区分明細名, 区分明細1.区分明細名, 区分明細2.区分明細名, 取引先1.取引先略名 as 取引先略名1, 取引先2.取引先名称 as 取引先名称 from 受注残 LEFT JOIN 取引先 on 受注残.得意先番号 = 取引先.取引先番号 LEFT JOIN 担当者 on 受注残.売上担当者 = 担当者.担当者番号 LEFT JOIN 区分明細 On ( 受注残 .受注伝票区分 = 区分明細.区分明細番号) LEFT JOIN 区分明細 as 区分明細1 On (受注残.仮単価区分 = 区分明細1.区分明細番号) LEFT JOIN 区分明細 as 区分明細2 On (受注残.完納区分 = 区分明細2.区分明細番号) LEFT JOIN 取引先 as 取引先1 on (受注残.得意先番号 = 取引先.取引先番号 ) LEFT JOIN 取引先 as 取引先2 on (受注残.得意先番号 = 取引先.取引先番号 ) where ('00001' = '99999' OR ('00001' <> '99999' AND 受注残.工場番号 = '00001')) and 受注残.受注日 between '2008/08/29' and '2008/09/01' AND (区分明細.区分番号 = '01' Or 区分明細.区分番号 Is Null) AND (区分明細1.区分番号 = '40' Or 区分明細1.区分番号 Is Null) AND (区分明細2.区分番号 = '10' Or 区分明細.区分番号 Is Null) AND 取引先1.取引先番号 = '00001' AND 取引先2.取引先番号 = '00001' AND 取引先.得意先番号 = '12' --出力順 order by 受注残.工場番号, 受注残.得意先番号, 受注残.品目番号, 受注残.受注日, 受注残.受注番号

専門家に質問してみよう