- ベストアンサー
Accessで縦に情報が展開されてるテーブルの処理
作業環境は以下の通りで、Accessの知識は初心者です。 OS:Windws7/使用ソフト:Access2003 やりたい事はこれに近いのですが、もう一ひねりある為困っています。 http://okwave.jp/qa/q2452277.html?from=recommend テーブルに以下のようなデータがあります。 薬剤/配番/効果/使用方法 A剤/00001/頭痛/1回1錠 A剤/00002/発熱/食後…(長文) B剤/00001/頭痛/1回2錠 B剤/00003/裂傷/清潔な手で…(長文) これを薬剤名ごとに、効果(数は120を超えます)と使用方法を横へ並べる事はできますか?
- みんなの回答 (15)
- 専門家の回答
質問者が選んだベストアンサー
#9です > 実行時エラー'94': > Nullの使い方が不正です > > デバックボタンを押してみると55行目の↓この部分が黄色く反転されました。 > sA(i * 2 - 1) = rs("効果") おそらく、「効果」にデータが無くて Null になっていると思われます。 ※ データ/テーブル内容からすると、何かしら設定されているものと思っていたんですが・・・ 対処方法は2つあって、 1)代入する時に Nz 関数を使って Null を ""(空文字)に置換える > sA(i * 2 - 1) = rs("効果") > sA(i * 2) = rs("使用方法") ↓ sA(i * 2 - 1) = Nz(rs("効果")) sA(i * 2) = Nz(rs("使用方法")) ただ、これには問題がありそう というのは、両方値が入っていなければ良いと思いますが、 どちらか一方だけに値が設定されていたら・・・ 変な内容に? 2)必ず「効果」「使用方法」両方に値が設定されているものを対象にする > Const CSQL1 As String = "SELECT DISTINCT 配番 FROM {%1};" > Const CSQL2 As String = "SELECT * FROM {%1} ORDER BY 薬剤;" これで抽出しているわけですが、 条件として「効果」「使用方法」とも設定されているもの・・・ を、追加します。 Const CSQL1 As String = "SELECT DISTINCT 配番 FROM {%1} " _ & "WHERE 効果 Is Not Null AND 使用方法 Is Not Null;" Const CSQL2 As String = "SELECT * FROM {%1} " _ & "WHERE 効果 Is Not Null AND 使用方法 Is Not Null ORDER BY 薬剤;" これに変更すると、1)での変更は不要です。 けど、念のために1)も適用しておいた方が良いかも この修正でどうなりますでしょうか
その他の回答 (14)
- 30246kiku
- ベストアンサー率73% (370/504)
#14です 結果を教えていただき、ありがとうございます > 単純に入力忘れと思われます > Nullの配番は様々という事になります 手間を取らせてしまった様で、すみません。 心配性なもので・・・ 効果 Null は継続用途? と疑ったわけですが、 継続のやり方は、 ・#14での、配番+1 とする方法のほかに、 ・同じ薬剤に、同じ配番を存在させ、薬剤を昇順、配番を昇順、効果を降順で並ばせる が考えられたので、効果 Null の配番も合わせて調べられたら・・・・ と記述したつもりでした (そう伝わっていなかったら、ごめんなさい) でも、 > 単純に入力忘れと思われます であれば、#14 の VBA は忘れてください。 また、#12の2)は、効果 Null のものを除外していますが、 同じ配番で、例えば、効果が「注意」「ご注意」 Null のものは、 同じ項目「効果xx」で縦に並ぶので、何箇所かが空欄になっていても 前後関係で理解できる?ものなのかと・・・ であれば、2)ではなく、1)の方が良かったりして・・・ ・効果 Null のものは除外する ・使用方法だけでも盛り込む これは、質問者さんの判断になるかと思います。 なお、#12の2)での > AND 使用方法 Is Not Null 部分は削除しても良いかも 余談) 他ご質問への#12を使った展開は、 ・配番の順で記述位置を管理するのは同じ。 ただし、見出しに使う文字列は、同一配番での効果の一番短い物を使うとか 同一配番で、例えば、効果が「注意」「ご注意」なら「注意」の方を見出しに とでもすれば、列数は今回のものの半分程度になるかと・・・ ※ 「注意」「ご注意」を別々の列にしようとするから、2000 項目以上になるのかも ※ 単に文字列として見出しを作る事は出来ますが > 効果(230文字程度、全角文字と半角英数字と-./()・などの記号が含まれる) より、 他システムが見出しとして解釈できない文字を編集する必要があると思います。 (問題なければ編集は不要ですけど・・・:心配性なもので・・・) 以上 失礼しました
お礼
こんにちは。 1)の方法での処理はこんな感じになりました。 レコード:455531 処理時間:10分 CSVサイズ:169MB CSV行数:108012 空欄を含めた事で10フィールド程増えた為、時間とCSVサイズが少し増えたようです。 覚えるのは容易ではなさそうですがAccessの基本が理解できたらVBAも勉強しようと思います。 この度は本当にありがとうございました。
補足
回答ありがとうございます。 > 同じ薬剤に、同じ配番を存在させ、薬剤を昇順、配番を昇順、効果を降順で並ばせる なるほど、そんな方法もあったのですね。 全然気づかずすみませんでした… > これは、質問者さんの判断になるかと思います。 はい、前後関係で理解できるものもあります。 その為、1)の方法で問題ない事がわかりました。 数も50個程度なので私の判断で適宜埋めてしまっても大した労力もなさそうですが… > ただし、見出しに使う文字列は、同一配番での効果の一番短い物を使うとか そんなことも調整できるのですね! そういった例は複数見かけました。 また今日気づいたのですが、配番は違うけど効果が重複してしまっているものなどありました。 > 他システムが見出しとして解釈できない文字を編集する必要があると思います。 説明欄の入力場所はこれらの記号が問題なく入るので、編集する手間は省けそうです^^ 折角修正して頂いたのに、情報後出しになってしまったりでお手間をとらせてしまい申し訳ございません。 説明してもらってやっと気づくなんてAccess知識がない云々のレベルじゃないですね>< 明日にでも1)の方法の結果などご報告いたしますね!
- 30246kiku
- ベストアンサー率73% (370/504)
#12です > 効果のみNull値が存在するようです これ、結構引っ掛かってました。 #12での対処は安易だったかもしれません。 > 使用方法フィールドはメモ型 これを一旦疑う方向で考えてみると・・・ インポートする前のテキストファイル内の使用方法は、 ある程度の文字数で区切られていて・・・ 継続する為に、例えば、配番を+1して、効果を Null また、使用方法には続きを・・・ こう考えてみると、効果 Null の役割はあるのかな? ※※ 何故、効果の Null が存在するのか確認してください ※※ ※ また、効果が Null の配番は何?は、調べておいた方が良いと思います もしそうであれば、インポートした後に 使用方法を繋げて、効果 Null のものは削除するとか必要だったのかも・・・ 現状のデータ状態で、上記の使用方法継続と考えた記述は以下になりますが、 上記推測で文字数で区切ったのには理由があると思うので確認は必須です。 なお、上記推測での使用方法継続を捨てるのなら、#12のままでも #9からの変更点は、 ・配番の順で記述位置を決定する時には、効果が Null じゃないもので ・記述位置を求める際 効果が Null じゃなかったら、それ用の記述位置を求める 効果が Null だったら、前回の位置に これ用に、変数 iPos もちろん、効果 Null の出現位置は、配番順と仮定するので ORDER BY 薬剤, 配番 として、配番の昇順も指定する様に 継続の使用方法は、配番+1と仮定していましたが、これが外れた場合 順を特定できないので、最悪の場合だけ処理する様に (配番に -1 が存在するみたいで、何の用途か不明) (配番は正と、勝手に思い込んでいたので) Public Function Samp2() Dim dic As Object Dim rs As DAO.Recordset Dim sA() As String Dim sSql As String Dim vSave As Variant Dim iPos As Long, i As Long Dim ffn As Integer Const CTABLE As String = "テーブル名" ' ← 変更要 ★ Const CFILE As String = "\testSamp1.csv" ' ← 変更要 ★ Const CSQL1 As String = "SELECT DISTINCT 配番 FROM {%1} " _ & "WHERE 効果 Is Not Null;" Const CSQL2 As String = "SELECT * FROM {%1} ORDER BY 薬剤, 配番;" Set dic = CreateObject("Scripting.Dictionary") sSql = Replace(CSQL1, "{%1}", CTABLE) Set rs = CurrentDb.OpenRecordset(sSql) While (Not rs.EOF) dic(rs("配番").Value) = rs.AbsolutePosition + 1 rs.MoveNext Wend rs.Close Set rs = Nothing ReDim sA(dic.Count * 2) ffn = FreeFile() Open CurrentProject.Path & CFILE For Output As #ffn sA(0) = "薬剤" For i = 1 To dic.Count sA(i * 2 - 1) = "効果" & i sA(i * 2) = "使用方法" & i Next Print #ffn, Join(sA, ",") For i = 0 To UBound(sA) sA(i) = "" Next sSql = Replace(CSQL2, "{%1}", CTABLE) Set rs = CurrentDb.OpenRecordset(sSql) While (Not rs.EOF) If (vSave <> rs("薬剤").Value) Then If (Not IsEmpty(vSave)) Then For i = 0 To UBound(sA) - 1 Write #ffn, sA(i), sA(i) = "" Next Write #ffn, sA(i) sA(i) = "" End If vSave = rs("薬剤").Value sA(0) = vSave iPos = 0 End If If (Not IsNull(rs("効果"))) Then iPos = dic(rs("配番").Value) If (iPos > 0) Then i = iPos * 2 sA(i - 1) = sA(i - 1) & rs("効果") sA(i) = sA(i) & rs("使用方法") End If rs.MoveNext Wend If (Len(sA(0)) > 0) Then For i = 0 To UBound(sA) - 1 Write #ffn, sA(i), Next Write #ffn, sA(i) End If Close #ffn rs.Close: Set rs = Nothing Set dic = Nothing End Function ※ 処理速度がどの程度だったのか気になります。 よろしければ、どの位・・・ 教えていただければと思います。 レコード:何件、CSV行数:何行、サイズ、何分位・・・とか
お礼
遅くなりまして申し訳ございません。 元のテキストファイルを仮に「説明.txt」とします。 「説明.txt」はホームページ上の薬剤の説明欄へ入力する情報が入っております。 【説明.txt】 薬剤(8文字の半角英数字の組み合わせ) 配番(1桁のマイナスの値から1000程度の値までの数字) 効果(230文字程度、全角文字と半角英数字と-./()・などの記号が含まれる) 使用方法(最大2500文字程度で、全角文字と半角英数字と-./()・,などの記号が含まれる) > こう考えてみると、効果 Null の役割はあるのかな? > ※※ 何故、効果の Null が存在するのか確認してください ※※ > ※ また、効果が Null の配番は何?は、調べておいた方が良いと思います 「説明.txt」を開いて確認してみましたところ、該当薬剤の効果がタブになってますので、単純に入力忘れと思われます。 その為、Nullの配番は様々という事になります。 と、申し上げますのも配番は説明欄の中での表示順位です。 配番=効果でもあります。その為、効果名が多少違くても同じ意味合いのものは配番が一致します。(実際そういうものもあります)そして配番にはNullが存在しません。 なぜマイナスの値があるのかについては当初、1の情報を1番上に表示させたかったが、それよりも重要な情報が出てきた為マイナスの値を作るようになった為のようです。 > よろしければ、どの位・・・ 教えていただければと思います。 これは#12での処理の事になりますが レコード:455531 処理時間:5分未満 CSVサイズ:166MB CSV行数:108012
補足
すみません、自社のデータでは無いのと参照URLに沿ってしまった為、重要な情報が抜けてしまった事で2度手間になってしまいましたね… null値がなぜ存在したか考えてもいませんでした。 恐らく、使用方法にカンマが存在してるからかもしれません。 その他の情報として、使用方法はメモ型で2500字以内に収まる内容です。 現在自宅の為、確かな事は申し上げられませんので、明日にでも他含めて正しい情報に修正します。 そして回答12のVBAですが、レコード数108012、5分未満で処理は終了しました。 csvの行数とサイズは明日、確認しますね。
- NotFound404
- ベストアンサー率70% (288/408)
なるほど・・・。 原因を究明したいところですが、#9さんの回答でバッチリのようですので これは私の個人的な宿題とさせていただきます。 つたない回答にお付き合いいただきましたこと恐縮です。
お礼
いいえ、こちらこそ画面上のやり取りだけで言わんとした事を組み立て、形にするべく試行錯誤して頂いてお礼申し上げます。 HTMLをかじった私の話ですが、人様が書いて下さったコードを見て、触るのは本当に勉強になりました。(今もなおのことですが) どこまで極められるのかわかりませんが、いづれ私もこの2つのVBAを読み返して、懐かしく思える日がくる事を楽しみに勉強を始めようと思います^^
- NotFound404
- ベストアンサー率70% (288/408)
処理速度はかなり改善していると思いますが未検証です。 メモリ不足でパンクするかも? ※成否に関わらず結果(エラーメッセージになるかも?)を教えてください。 前回の関数を下記に差し替えてください。 では。 Function JoinCSV() '要参照設定Microsoft ActiveX DataObject Library 2.5以上 Dim Cn As ADODB.Connection Dim RsK As ADODB.Recordset Dim RsS As ADODB.Recordset Dim i As Long, j As Long, k As Long Dim sSql As String Dim FF As Integer Dim RowTmp() As String Dim csvRows() As String Const dLim As String = """,""" Dim csvAll As String Set Cn = CurrentProject.Connection Set RsK = New ADODB.Recordset sSql = "TRANSFORM " _ & "First(Tbl.[効果]) AS 効果の先頭 " _ & "SELECT Tbl.[薬剤] " _ & "FROM Tbl " _ & "GROUP BY Tbl.[薬剤] " _ & "PIVOT '効果' & Tbl.[配番];" RsK.Open sSql, Cn, adOpenStatic, adLockReadOnly Set RsS = New ADODB.Recordset sSql = "TRANSFORM " _ & "First(Tbl.[使用方法]) AS 使用方法の先頭 " _ & "SELECT Tbl.[薬剤] " _ & "FROM Tbl " _ & "GROUP BY Tbl.[薬剤] " _ & "PIVOT '使用方法' & Tbl.[配番];" RsS.Open sSql, Cn, adOpenStatic, adLockReadOnly ReDim RowTmp(RsK.Fields.Count * 2 - 2) ReDim csvRows(RsK.RecordCount) 'ヘッダー取得 For i = 0 To RsK.Fields.Count - 1 RowTmp(j) = RsK.Fields(i).Name j = j + 1 If j > 1 Then RowTmp(j) = RsS.Fields(i).Name j = j + 1 End If Next csvRows(0) = Join(RowTmp, ",") '配列をJoinで一行に '各データ取得 k = 1 ' 0 はヘッダーで使用済み Do Until RsK.EOF ReDim RowTmp(RsK.Fields.Count * 2 - 2) j = 0 For i = 0 To RsK.Fields.Count - 1 RowTmp(j) = IIf(i = 0, """", "") _ & Nz(RsK.Fields(i).Value, "") '最初なら行頭に " を付加 j = j + 1 If j > 1 Then RowTmp(j) = Nz(RsS.Fields(i).Value, "") _ & IIf(i = (RsK.Fields.Count - 1), """", "") '最後なら行末 " を付加 j = j + 1 End If Next csvRows(k) = Join(RowTmp, dLim) 'Debug.Print i, csvRows(k) k = k + 1 RsK.MoveNext RsS.MoveNext Loop csvAll = Join(csvRows, vbCrLf) FF = FreeFile Open CurrentProject.Path & "\JoinCSV.csv" For Output As #FF Print #FF, csvAll Close #FF RsS.Close: Set RsS = Nothing RsK.Close: Set RsK = Nothing Cn.Close: Set Cn = Nothing Msgbox "終了しました" End Function
補足
回答ありがとうございます。 今回テスト環境では成功し、本番環境ではこのようになりました。 実行時エラー'52': ファイル名または番号が不正です デバックボタンを押してみると75行目の↓この部分が黄色く反転されました。 Print #FF, csvAll そのまま終了し、記録されたところまでのCSVを開いてみると、ヘッダーが途中まで作成されていました。 薬剤/効果-1/使用方法-1/効果10/使用方法10/効果2/使用方法2/効果28/使用方法28/… ※質問の都合上、「配番」としたものは本番環境では不規則な数字が入っている為、このような表示になっています。 ちなみにこの数字は表示される順位の事を指しています。 なお、ヘッダー以外の情報は入っておりませんでした。 私が伝えた情報が不足しているのか、データ量がすごく多いのか、何度もお手数おかけしてすみません。
- ki073
- ベストアンサー率77% (491/634)
No.9の30246kikuさんに続いて、横からすみません。 データ量ですが、およそ薬剤11万種類×効果120種類というとなのでしょうか? そうすると1つが100バイトとしても、ファイルサイズで1.3Gバイトかそれ以上となるのでしょうか? 全部読むのはかなり苦しそうですね。A剤が続いていて、それが終わったらB剤になるようにかたまっているのでしたら、順番に読み込んでいって、1薬剤ごとに処理するのが早そうです。(かたまってなければあらかじめソートする) エクセルであらかじめソートするのも大きすぎて無理なのかな?? Accessは全くの素人なのですが、インデックスを設定しているのでしょうか? それともリレーションを設定した時点でインデックスはつくられるのでしょうか?
補足
回答ありがとうございます。 > データ量ですが、およそ薬剤11万種類×効果120種類 その通りです。 元データはテキストファイルで、それをAccessにインポートしました。 元のテキストファイルは、99.4MBです。 > 順番に読み込んでいって、1薬剤ごとに処理 はい、薬剤ごとに固まっております。 > インデックスを設定しているのでしょうか? 特に設定していませんし、インデックスという言葉も初めて耳にしました。
- 30246kiku
- ベストアンサー率73% (370/504)
おじゃまします 記憶だけなのですが、 一気に書き出し・・・は、ソコソコの文字数であれば速くて 大容量になるとかえって遅くなったような気がします。 (嘘を言っているかもしれません) 大量レコードでのクロス集計2発&CSV書出しを クロス集計もどきを自力&1行毎の書き出しにしてみました。 ※ 列の並び順が変わるかも・・・ ★ 部分を変更の上実行してみてください。 Public Function Samp1() Dim dic As Object Dim rs As DAO.Recordset Dim sA() As String Dim sSql As String Dim vSave As Variant Dim i As Long Dim ffn As Integer Const CTABLE As String = "テーブル名" ' ← 変更要 ★ Const CFILE As String = "\testSamp1.csv" ' ← 変更要 ★ Const CSQL1 As String = "SELECT DISTINCT 配番 FROM {%1};" Const CSQL2 As String = "SELECT * FROM {%1} ORDER BY 薬剤;" Set dic = CreateObject("Scripting.Dictionary") sSql = Replace(CSQL1, "{%1}", CTABLE) Set rs = CurrentDb.OpenRecordset(sSql) While (Not rs.EOF) dic(rs("配番").Value) = rs.AbsolutePosition + 1 rs.MoveNext Wend rs.Close Set rs = Nothing ReDim sA(dic.Count * 2) ffn = FreeFile() Open CurrentProject.Path & CFILE For Output As #ffn sA(0) = "薬剤" For i = 1 To dic.Count sA(i * 2 - 1) = "効果" & i sA(i * 2) = "使用方法" & i Next Print #ffn, Join(sA, ",") For i = 0 To UBound(sA) sA(i) = "" Next sSql = Replace(CSQL2, "{%1}", CTABLE) Set rs = CurrentDb.OpenRecordset(sSql) While (Not rs.EOF) If (vSave <> rs("薬剤").Value) Then If (Not IsEmpty(vSave)) Then For i = 0 To UBound(sA) - 1 Write #ffn, sA(i), sA(i) = "" Next Write #ffn, sA(i) sA(i) = "" End If vSave = rs("薬剤").Value sA(0) = vSave End If i = dic(rs("配番").Value) sA(i * 2 - 1) = rs("効果") sA(i * 2) = rs("使用方法") rs.MoveNext Wend If (Len(sA(0)) > 0) Then For i = 0 To UBound(sA) - 1 Write #ffn, sA(i), Next Write #ffn, sA(i) End If Close #ffn rs.Close: Set rs = Nothing Set dic = Nothing End Function やっている事は、 ・配番の昇順で、その配番のものは何個目に配置する・・・ これを Dictionary で 1 ~ の連番で管理するようにして ・薬剤順で並べたレコードを順に処理して、 薬剤が変わったら、1行書出し その途中のデータを作り込む配列が sA sA(0) には薬剤、sA(1) には 効果1 、sA(2) には 使用方法1 sA(3) ~ は、添え字奇数部分が効果、偶数部分が使用方法 ヘッダの書き出しでは、"" で囲まないとのことなので sA を ,(カンマ)で繋げたものを Print 以降の行は "" で囲むことから Write (元のデータが文字列なので "" で囲まれる) (逆に "" で囲んでもらいたいので String の配列を利用) ※ 大量データでは確認していないので、遅かったりしたらごめんなさい 余談) 大量のデータを順に処理したい時には DAO を使った方が良さそうです ADO では、全部のデータを用意するまで Open から先に進まないような・・・ DAO では、Open から先に進むまでが速い様な・・・ (私の感覚だけなので、嘘かも)
お礼
回答ありがとうございます。 処理の解説までしていただいてありがとうございます。 後ほどゆっくり調べてみようと思います。 テーブル名と、CSV名と、マクロのプロシージャ名を変更し、テスト環境では成功したのですが、本番環境だと下記のエラーが返ってきます。 実行時エラー'94': Nullの使い方が不正です デバックボタンを押してみると55行目の↓この部分が黄色く反転されました。 sA(i * 2 - 1) = rs("効果") そのまま終了し、記録されたところまでのCSVを開いてみると、各フィールドと列の並び順は全て希望の通り作成されています。 薬剤/効果1/使用方法1/効果2/使用方法2/…使用方法122 薬剤のそれぞれの情報も、各セルに収まっています。 以上の事から4369行までは正常に情報が処理されたようなのですが、なぜこのエラーが返ってきたのか分かりません。 重ねての質問で大変申し訳ございませんが、どういった事がこのエラーにつながったのかお解かりでしたら教えて頂けないでしょうか。
- NotFound404
- ベストアンサー率70% (288/408)
すみません。 #6のコードの後半の Write #FF ,buf を Print #FF ,buf に修正してください。 これでひとつに収まってしまう問題は解決するハズです。 時間が掛かる件について。 Buf(メモリ)に一旦全て読み込んでから一度にファイルに書き出し・・・ を考えていましたが、11万レコード位になっているとのことですので タスクマネージャーで観察するとメモリを厳しく圧迫しているハズです。 改善策を模索中です。(期待しないでください。) という訳で今晩の回答はお休みさせてください。
お礼
回答ありがとうございます。 > Print #FF ,buf この1行でファイルにデータを書き出す命令をしてるんですね! こういった操作に関しての宣言や語句(?)はかなり数多くあると思うのですが、全部覚えていらっしゃるのでしょうか? 私は英語など中学生レベルでも怪しいので、プログラミングなどの英語を羅列して処理させる類のものは最初がとっつきにくくて^^; HTMLをかじっているのですが、文法を覚える位で後は便利なものでエディタ上のボタン操作でタグを吐き出してくれます。 多少のタグは何度も使ううちに覚えましたが、VBAはHTMLとは比べ物にならない位難しそうですね… 11万レコードというのはやはり処理が重いのですね。 本来ならば講習を受けたり、業者に依頼する案件のところを、こうして善意で教えて頂き大変感謝しております。 Accessを使いこなせるようになれば、可能性は0でないことが分かっただけでも収穫です^^ 自分でも分かる範囲で試行錯誤してみます!
- NotFound404
- ベストアンサー率70% (288/408)
>3時間かかっても終了せず・・・ 途中で強制終了してしまったということでしょうか? テーブルのレコード数はどれ位でしょう? あと、Q効果クエリを削除していなければ開いて 左下に、レコード位置/総レコード数が表示されますが レコード数が表示されるまでの時間と表示された時のレコード数はどれ位でしょう? Q効果とQ使用方法から中間テーブルを作成してからの方が安全かもしれません。 ただ、私の手に負えないような気がしてきました。。。
お礼
回答ありがとうございます。 > 途中で強制終了してしまったということでしょうか? いいえ、別の用途でAccessを使用する都合が出来た為、途中でキャンセルしました。 > レコード数が表示されるまでの時間と表示された時のレコード数はどれ位でしょう? 表示時間は30秒かからない程度で、レコード数は108012となっております。 テスト環境(5レコード程度)でJoinCSV.csvとして吐き出された物をCSVエディタで開くと、1セルの中に全ての情報が入っていたのですがその為でしょうか? テキストエディタで開くと薬剤に対して横1行づつ展開したので気にしなかったのですが…
- NotFound404
- ベストアンサー率70% (288/408)
こんな感じかな。例外処理的なモノ、エラー処理が含まれていません。 Accessデータファイルと同じフォルダにJoinCSV.csv が作成されます。 検証は十分に行ってください。 手順。 Alt + F11 でVBEのウィンドウにします。 メニューのツール → 参照設定 を選択。 ライブラリの一覧が出ますので、Access2003なら (Microsoft ActiveX DataObject Library 2.5 以降だと思います) にチェックを入れて、OK で閉じます。 メニュー → 挿入 → 標準モジュール を選択。 新たなウィンドウが出ますので下記コードをコピペ。 メニュー → デバッグ → ○×△のコンパイルを選択。 何も起きなければ OK です。 Ctrl + S でファイルの上書き保存します。 モジュール名を聞いてくるので、適当な名前を付けてください。 Alt + F4 でVBE を閉じます。 『マクロ』の新規作成から アクション に「プロシージャの実行」、 下のプロシージャ名に、JoinCSV() とします。 マクロを適当な名前で保存します。 そのマクロを実行すれば、csv ファイルが出来ます(多分)。 なお、クエリ(Q薬剤・Q効果・Q使用方法)は不要です。 Function JoinCSV() '要参照設定Microsoft ActiveX DataObject Library 2.5以上 Dim Cn As ADODB.Connection Dim RsK As ADODB.Recordset Dim RsS As ADODB.Recordset Dim i As Integer Dim sSql As String Dim Buf As String Dim FF As Integer Set Cn = CurrentProject.Connection Set RsK = New ADODB.Recordset sSql = "TRANSFORM " _ & "First(Tbl.[効果]) AS 効果の先頭 " _ & "SELECT Tbl.[薬剤] " _ & "FROM Tbl " _ & "GROUP BY Tbl.[薬剤] " _ & "PIVOT '効果' & Tbl.[配番];" RsK.Open sSql, Cn, adOpenStatic, adLockReadOnly Set RsS = New ADODB.Recordset sSql = "TRANSFORM " _ & "First(Tbl.[使用方法]) AS 使用方法の先頭 " _ & "SELECT Tbl.[薬剤] " _ & "FROM Tbl " _ & "GROUP BY Tbl.[薬剤] " _ & "PIVOT '使用方法' & Tbl.[配番];" RsS.Open sSql, Cn, adOpenStatic, adLockReadOnly For i = 1 To RsK.Fields.Count Buf = Buf & RsK.Fields(i - 1).Name & "," If i > 1 Then Buf = Buf & RsS.Fields(i - 1).Name & "," End If Next Buf = Left(Buf, Len(Buf) - 1) Do Until RsK.EOF Buf = Buf & vbCrLf For i = 1 To RsK.Fields.Count Buf = Buf & """" & RsK.Fields(i - 1).Value & """" & "," If i > 1 Then Buf = Buf & """" & RsS.Fields(i - 1).Value & """" & "," End If Next Buf = Left(Buf, Len(Buf) - 1) RsK.MoveNext RsS.MoveNext Loop FF = FreeFile Open CurrentProject.Path & "\JoinCSV.csv" For Output As #FF Write #FF, Buf Close #FF RsS.Close: Set RsS = Nothing RsK.Close: Set RsK = Nothing Cn.Close: Set Cn = Nothing Msgbox "終了しました。" End Function
お礼
回答ありがとうございます。 VBAの手順まで示して下さってありがとうございます。 早速テスト環境でマクロを実行してみたところ、一瞬でやりたかった事が終了してしまいました! 本番環境(データ量も多く、フィールド名などが違う)では3時間かかっても動作が終了せず、やはりラクして手に入れたものは身についていないという事もあり、修正するのも大変だなぁ、と痛感しております。 以前に書いて頂いたSQL文が入っていた為、VBAでQ効果とQ使用方法の集計クエリを作って、最後にJoinCSV.csvとして吐き出す処理を指定しているのはなんとなく分かりましたが、その間の命令などが全然理解できていないです^^; まずはこのまま利用させて頂き、このおかげで空いた時間を使ってAccessの勉強をしたいと思います。 本番環境の修正が終わり、正常に動作しましたら後日こちらにご報告いたしますね!
- NotFound404
- ベストアンサー率70% (288/408)
まず、#4 の差し替えですが確認したところ、 256文字以降が切り捨てられてしまいますので Q使用方法は元に戻してください。 TRANSFORM First(Tbl.[使用方法]) AS 使用方法の先頭 SELECT Tbl.薬剤 FROM Tbl GROUP BY Tbl.薬剤 PIVOT '使用方法' & Tbl.[配番]; で、 >「このフォームまたはレポートは、1つのレコードのデータの制限を超えるクエリを基にしています」 また、使用方法の中に半角カンマ , がある可能性も考えてしまいます。 なので、VBA で処理するしかありません。 (Excel2007以降があれば、 Q効果とQ使用方法をExcelに出力して列を切り貼りして整形後にCSV出力・・も考えられますけど。。) VBA での処理でも構わなければ、 CSV で出力した時のフォーマットを教えてください。 各フィールドはダブルクォーテーションで囲むのか。 "A剤","頭痛","1回1錠","発熱","食後…(長文)", 値が無い場合にもダブルクォーテーションが必要か否か。 "A剤","頭痛","1回1錠","発熱","食後…(長文)", を↓ "A剤","頭痛","1回1錠","","", 必要例 "A剤","頭痛","1回1錠",,, 不要例 ヘッダー(タイトル)が必要か否か。(これも囲みの有無) 薬剤/効果1/使用方法1/効果2/使用方法2 /効果3/使用方法3 /・・・ 文字コードは、Shift_JIS で良いのか。 他にも何かあれば、それも含めて確認し、教えてください。
お礼
回答ありがとうございます。 > Q使用方法は元に戻してください。 私の回答によりSQL文を差し替えて下さったのにすみません… 早速元に戻しました。 > また、使用方法の中に半角カンマ , がある可能性も考えてしまいます。 使用方法には半角カンマの他、ダブルクォーテーションが含まれており、改行は含まれておりません。 > なので、VBA で処理するしかありません。 カンマが含まれる場合はVBAでの処理になってしまうのですね。 SQL文は今後なんとか理解できそうな内容でしたが、VBAとなると今の私のレベルでは理解できるようになるのはかなり先の話です。 それなのにVBAを記述していただくのはありがたい事ですが、気が引けます… …が、折角なので質問に対する回答を記載しました。 > CSV で出力した時のフォーマットを教えてください。 フォーマットというのは以下の質問に答える形で間に合いますか? それともフィールドのデータ型みたいな内容が必要でしたでしょうか? > 各フィールドはダブルクォーテーションで囲むのか。 全てのフィールドをダブルクォーテーションで囲みます。 > 値が無い場合にもダブルクォーテーションが必要か否か。 値が無い場合もダブルクォーテーションが必要となります。 > ヘッダー(タイトル)が必要か否か。(これも囲みの有無) ヘッダーは必要で、ヘッダーのダブルクォーテーションは不要です。 > 文字コードは、Shift_JIS で良いのか。 Shift_JISで大丈夫です。 あと、区切り文字はカンマです。
- 1
- 2
お礼
回答ありがとうございます。 > おそらく、「効果」にデータが無くて Null になっていると思われます。 確認してみたところ確かにNull値がありました。 選択クエリで効果と使用方法と両方の3タイプにIs Nullで抽出をかけたところ、効果のみNull値が存在するようです。 その為、2)に変更してみたところ、希望通り横に展開されました!! ありがとうございます。 処理の解説も頂いていましたので、落ち着いたら本格的にAccessの勉強を始めたいと思います。 (排出されたCSVをもう一加工する為に他のソフトとの連携設定を考えなくてはならないのです…)