• ベストアンサー

vbaで質問です

初めて質問させていただきます。エクセルvbaで質問です。 Aというテーブルに名前 idという列があり名前は複数のidを持っていて名前とidは重複してるものもあります。そこから 名前が一緒でidが違うid そのidを名前ごとに一つのセルに出力したいのですが、可能でしょうか? かなり初心者で質問の情報もこれぐらいしか出てこないほどです。 申し訳ありませんがご教授ください。

質問者が選んだベストアンサー

  • ベストアンサー
  • AKARI0418
  • ベストアンサー率67% (112/166)
回答No.5

ソースを解析して工夫してみてください。 ソースが少し読めればすぐに解決できるはずです。 For j = 0 To RecordSet.RecordCount - 1 Worksheets(SummarySheet).Cells(i + SummaryRow, SummaryColumn + j + 1).Value = RecordSet("ID").Value RecordSet.MoveNext Next j この部分がリストを出力している部分になります個々を改造すればIDをひとつのセルにまとめることができます。 この部分を改造するために解説します。 まずRecordSetはstrSQL = "SELECT * FROM A"の実行結果が格納されています。 "SELECT * FROM A"はSQLと呼ばれる言語で、ACCESS等のデータベースエンジンとVBなどのプログラミング言語の橋渡しをしてくれます。 ここで使用しているのはSELECT構文(抽出構文)です。 SELECT 項目名 FROM テーブル名となります。 項目名の変わりに"*"を使用することで、全ての項目を抽出対称にすることができます。 "SELECT * FROM A"は"SELECT 名前, ID FROM A"おなじ意味ということになります。 要するにRecordSetにはテーブルAの全ての項目が格納されているということです。 RecordSet.Filterメソッドを使用し、ある名前のものだけを使用できるようにさらに抽出をかけています。 For j = 0 To RecordSet.RecordCount - 1 For~Nextはカウンタ使用のループ構文です、jが0からRecordSet.RecordCount - 1まで繰り返します。 RecordSet.RecordCountは字の如しですが、レコード数を照会するメソッドです。 つまり、テーブルAのレコード数処理を繰り返すということになります。 Worksheets(SummarySheet).Cells(i + SummaryRow, SummaryColumn + j + 1).Value は指定したワークシートの特定のセルの表示されている値を表します。 SummarySheet=シート名 ここでiは名前のリストの何人目かをあらわしています。 SummaryRow=集計開始行 今出力しようとするIDが何人目なのかおよび集計開始行がわかれば出力位置を特定できますよね。 SummaryColumn=集計開始列 jはある名前のIDのレコード数 今出力しようとするIDが何件目のIDなのかおよび集計開始列がわかれば出力位置を特定できます、ただし名前も出力しているので+1となるわけです。 ここでIDをひとつのセルにまとたいと考えて見ましょう。 修正箇所が大体イメージできますでしょうか? とりあえず Worksheets(SummarySheet).Cells(i + SummaryRow, SummaryColumn + j + 1).Value はjがカウントアップしてしまうので、修正しなければいけませんよね。 出力位置は名前の隣ですので Worksheets(SummarySheet).Cells(i + SummaryRow, SummaryColumn + 1).Value にIDを連結したものを出力するということになります。 For j = 0 To RecordSet.RecordCount - 1 Worksheets(SummarySheet).Cells(i + SummaryRow, SummaryColumn + j + 1).Value = RecordSet("ID").Value RecordSet.MoveNext Next j 1回の出力ですむのでループの外に出します。 For j = 0 To RecordSet.RecordCount - 1 RecordSet.MoveNext Next j Worksheets(SummarySheet).Cells(i + SummaryRow,SummaryColumn + 1).Value = RecordSet("ID").Value 次に出力したいデータですが、RecordSet("ID").ValueではなくRecordSet("ID").Valueを全て連結したいものです。 連結を考えなければいけません。 連結するために変数を準備しましょう。 Dim StrJoint as string を変数の宣言が記述されている部分に記述してください。 VBで文字列は"で囲んで表現します。 例 "abc","12","漢字" 文字列の連結は&演算子または+演算子を使用することで連結可能です。 "abc" + "def" = "abcdef"となります。 StrJointにRecordSet("ID").Valueを全て格納するためには、どうすればよいでしょうか? もともとの処理が1セルずつIDを出力できていたことを考えると、ループの中で全てのIDを連結することができるということが創造できると思います。 For j = 0 To RecordSet.RecordCount - 1 StrJoint = RecordSet("ID").Value RecordSet.MoveNext Next j Worksheets(SummarySheet).Cells(i + SummaryRow,SummaryColumn + 1).Value = RecordSet("ID").Value こんなイメージになりますでしょうか? しかしこれでは連結はしていないので、StrJointに格納される値がループ毎に変わっていく処理になってしまいます。 変数の連結は以下のようになります。 StrJoint = "123" StrJoint = StrJoint & "abc" StrJointには"123abc"が格納されています。 したがって以下のようになります。 For j = 0 To RecordSet.RecordCount - 1 StrJoint = StrJoint & RecordSet("ID").Value RecordSet.MoveNext Next j Worksheets(SummarySheet).Cells(i + SummaryRow,SummaryColumn + 1).Value = RecordSet("ID").Value これでStrJointに全てのIDを格納できます。 出力データもStrJointに変えなければだめですね。 For j = 0 To RecordSet.RecordCount - 1 StrJoint = StrJoint & RecordSet("ID").Value RecordSet.MoveNext Next j Worksheets(SummarySheet).Cells(i + SummaryRow,SummaryColumn + 1).Value = StrJoint これで目的自体は達成できると思います、実行してみて結果をご覧ください。 ひとつ問題に気づくはずです。 IDの切れ目がわからず見にくいという問題です。 理想としては ID1,ID2,ID3,・・・・ のように出力したいですよね。 そこで連結時に","を一緒に連結すればよいと考えます。 For j = 0 To RecordSet.RecordCount - 1 StrJoint = StrJoint & RecordSet("ID").Value & "," RecordSet.MoveNext Next j Worksheets(SummarySheet).Cells(i + SummaryRow,SummaryColumn + 1).Value = StrJoint のような感じですね。 "" & "abc" & ","は"abc," このようなイメージで連結されていきます。 ここで再度実行してみましょう。 またがっかりされたと思います、確かに,区切りで出力され見やすくなったのですが、IDの最後にカンマが残ってしまっています。 ID1,ID2,ID3・・・・IDX, 今度は最後のカンマを消して出力するようにしましょう。 最後に出力する段階でカンマを消せればよいと考えます。 そこで文字列の部分参照を行います。 VBの部分参照関数はLEFT関数、RIGHT関数、MID関数の3種類です。 A = "abcdef" LEFT関数は左からX文字参照したいというものです。 LEFT(A,3)は"abc"を返します。 RIGHT関数は右からX文字参照したいというものです。 RIGHT(A,3)は"def"を返します。 MID関数はX文字目からY文字参照したいというものです。 MID(2,3)は"bcd"を返します。 さて最後の文字を削るためにはLEFT関数またはMID関数を使用すればよいことがわかります。 簡単なのでLEFT関数を使用します。 LEFT(対象文字列,参照文字数)というフォーマットでしたね、 対象文字列はStrJointですね、では参照文字数は何文字なのでしょうか? StrJointの文字数から1引いたものだというのはわかりますね。 では文字数を求めるにはLEN関数を使用します。 For j = 0 To RecordSet.RecordCount - 1 StrJoint = StrJoint & RecordSet("ID").Value & "," RecordSet.MoveNext Next j Worksheets(SummarySheet).Cells(i + SummaryRow,SummaryColumn + 1).Value = LEFT(strJoint,Len(strJoint)-1) となります。

bocchii
質問者

お礼

ご教授ありがとうございました。 なんと形にできそうです。自分で組む初めてのプログラムだったので勝手がわからず質問した次第でした。 本当にありがとうございました。

その他の回答 (4)

  • AKARI0418
  • ベストアンサー率67% (112/166)
回答No.4

Const SummarySheet As String = "Sheet2" Const SummaryRow As Long = 2 Const SummaryColumn As Long = 2 は出力位置を指します。 Sheet2のCells(2,2)つまり"B2"を書き出し位置としています。 Sheet2が存在しないためエラーになっていると思います。 書き出したいシート名に"Sheet2"を変更すればOKです。 Const SummarySheet As String = "書き出したいシート名" 書き出し位置もA3なら Const SummaryRow As Long = 3 Const SummaryColumn As Long = 1 書き出し位置もG5なら Const SummaryRow As Long = 5 Const SummaryColumn As Long = 7 といった感じです。

bocchii
質問者

補足

大体やりたいことはできたのですが、idが複数のセルになってしまいます。 出力した時に一つのセルにまとめるにはどうしたらいいでしょうか? あとidがid1 id2 id3に分かれていてそれも一つにまとめたい場合はどうしたらいいでしょうか? 度々申し訳ありませんがお願いいたします。

  • AKARI0418
  • ベストアンサー率67% (112/166)
回答No.3

先ほどのソースを使用するのでしたら、エクセルの機能であるメニューのデータ-外部データの取り込み-データの取り込みを行い、表形式にしてマクロを実行すれば実現できます。 せっかくDBなのですから、SQLを使用しての抽出をしてみてはいかがですか? 参照設定でMicrosoft ActiveX Data Objects 2.1以降を追加して実行してください。 Sub TableRead() Const DBPath As String = "C:\Documents and Settings\Administrator\My Documents\db1.mdb" Const SummarySheet As String = "Sheet2" Const SummaryRow As Long = 2 Const SummaryColumn As Long = 2 Dim cn As ADODB.Connection Dim NameRecordSet As ADODB.RecordSet Dim RecordSet As ADODB.RecordSet Dim strSQL As String Dim strCriteria As String Dim i As Long, j As Long Set cn = New ADODB.Connection cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" _ & "Data Source=" & DBPath cn.Open strSQL = "SELECT DISTINCT 名前 FROM A" Set NameRecordSet = New ADODB.RecordSet NameRecordSet.Open strSQL, cn, adOpenStatic, adLockReadOnly strSQL = "SELECT * FROM A" Set RecordSet = New ADODB.RecordSet RecordSet.Open strSQL, cn, adOpenStatic, adLockReadOnly For i = 0 To NameRecordSet.RecordCount - 1 strCriteria = "名前='" & NameRecordSet("名前").Value & "'" RecordSet.Filter = strCriteria Worksheets(SummarySheet).Cells(i + SummaryRow, SummaryColumn).Value = NameRecordSet("名前").Value For j = 0 To RecordSet.RecordCount - 1 Worksheets(SummarySheet).Cells(i + SummaryRow, SummaryColumn + j + 1).Value = RecordSet("ID").Value RecordSet.MoveNext Next j RecordSet.Filter = adFilterNone NameRecordSet.MoveNext Next i RecordSet.Close: Set RecordSet = Nothing NameRecordSet.Close: Set NameRecordSet = Nothing cn.Close Set cn = Nothing End Sub

bocchii
質問者

補足

worksheet(summrysheetのところでエラーとなるのですがどうしたらいいでしょうか?

  • AKARI0418
  • ベストアンサー率67% (112/166)
回答No.2

基本的なやり方としては、 1.1件ずつ名前をチェックし、重複のない名前の配列を取得する。 2.名前の回数全IDをチェックし、名前の等しいデーターを抽出する。 3.リストに書き出す。 2のつど3を行うことになると思います。 基本的なやり方は勉強なさってみてください、難しくはないと思います。 参考としてあまりベターなやり方ではない方法を紹介します。 Microsoft.Scripting.Runtimeを参照設定して実行してみてください。 Dictionaryクラスを使用して、重複を排除していく方法です。 Sub Summary() '名前列 Const NameColumn As Long = 1 'ID列 Const IDColumn As Long = NameColumn + 1 '出力先 Const SummarySheet As String = "Sheet2" Const SummaryRow As Long = 2 Const SummaryColumn As Long = 2 '遅延バインディングの場合 'Dim NameList As object 'Microsoft.Scripting.Runtimeを参照設定すること Dim NameList As New Scripting.Dictionary Dim StartRow As Long Dim EndRow As Long Dim WorkRange As Range Dim CheckRow As Long Dim WorkStr() As String Dim duplicationFlag As Boolean Dim i As Long, j As Long 'データー開始位置 StartRow = 2 '集計範囲格納 Set WorkRange = Range(Cells(StartRow, NameColumn), _ Range(ActiveSheet.Cells(65536, IDColumn), _ ActiveSheet.Cells(65536, IDColumn)).End(xlUp)) '遅延バインディングの場合 'Set NameList = CreateObject("Scripting.Dictionary") For i = 1 To WorkRange.Rows.Count CheckRow = i 'すでに名前が登録されているかをチェック If NameList.Exists(WorkRange.Cells(CheckRow, NameColumn).Value) = False Then NameList.Add WorkRange.Cells(CheckRow, NameColumn).Value, _ WorkRange.Cells(CheckRow, IDColumn).Value Else '初期化 Erase WorkStr duplicationFlag = False 'Dictionaryのアイテムを,区切りで配列に格納"a,b,c" → {"a","b","c"} WorkStr = Split(NameList.Item(WorkRange.Cells(CheckRow, NameColumn).Value), ",") '重複IDをチェック For j = 0 To UBound(WorkStr) - 1 If WorkStr(j) = WorkRange.Cells(CheckRow, IDColumn).Value Then duplicationFlag = True Exit For End If Next j '重複無しならアイテム追加,区切りで文字列連結"a,b,c" If duplicationFlag = False Then NameList.Item(WorkRange.Cells(CheckRow, NameColumn).Value) = _ NameList.Item(WorkRange.Cells(CheckRow, NameColumn).Value) & _ "," & WorkRange.Cells(CheckRow, IDColumn).Value End If End If Next i Set WorkRange = Nothing '集計 'Dictionaryのアイテム数ループ For i = 0 To NameList.Count - 1 'キー(名前)書き出し Worksheets(SummarySheet).Cells(i + SummaryRow, SummaryColumn).Value = NameList.Keys(i) '初期化 Erase WorkStr 'Dictionaryのアイテムを,区切りで配列に格納"a,b,c" → {"a","b","c"} WorkStr = Split(NameList.Item(NameList.Keys(i)), ",") 'ID書き出し For j = 0 To UBound(WorkStr) Worksheets(SummarySheet).Cells(i + SummaryRow, SummaryColumn + j + 1).Value = WorkStr(j) Next j Next i Set NameList = Nothing End Sub

bocchii
質問者

補足

回答ありがとうございます。 すみません、エクセルからではなくmdbから取得して、名前とidを 名前 id  ̄ ̄ ̄ ̄ ̄ ̄ ̄ | | | | | このように分けるとしたら可能でしょうか? 何度も申し訳ありません。

  • n-jun
  • ベストアンサー率33% (959/2873)
回答No.1

例題を提示された方がわかりやすいかも。

bocchii
質問者

補足

Aテーブル 名前 id  ̄ ̄ ̄ ̄ ̄ ̄ ̄ 田中 1234 田中 abcd 鈴木 4567 鈴木 ag365 佐藤 2j6 とこんな感じテーブルでそこから 田中 1234 abcd 鈴木 4567 ag365 佐藤 2j6 idを一つのセルにまとめたいのです。 あくまで例題なのでこれを応用して作りたいと思っているのですが…。 わかりづらかったらすみません。何卒お願いいたします。

関連するQ&A

  • EXCEL VBA テーブル間のコピー

    お世話になります。 VBA初心者です。 Excelで、元データであるSheet1にあるテーブルのB列をSheet2にあるテーブルのA列に転記したいと思います。このとき、Sheet2のテーブルにはデータが入っており、そのデータと重複するものを除外したものだけをSheet2テーブルの続きから入力させるにはどうしたらよいでしょうか? なにとぞご教授のほど、お願いいたします。

  • VBAで複数列セルに入力されている文字を一行に

    こんにちは。VBAにて下記イメージの複数列セルに入力されている文字を一行に変換しメモに出力すると同時に出力された一行の文字列をコピーした状態にしたいです。セルに記載された文字は「,」カンマで区切った状態で範囲はA3セルからA50位となります。また、セルが結合されていたり空白が存在したり様々です。大変申し訳御座いませんがご教授宜しくお願いします。 あああ → あああ,いいい,ううう,えええ,おおお・・・ いいい ううう  えええ おおお ・ ・ ・

  • Excel VBAで自動的にハイパーリンクを設定する方法について教えて

    Excel VBAで自動的にハイパーリンクを設定する方法について教えてください。 VBAについては、ほとんど初心者なので、どうやって良いのか分かりません。 やりたい作業については、あるExcelのブックに一覧表があり、その一覧表のIDと合致したファイルをハイパーリンクさせたいのです。 一覧表は、 ID    項目  ・・・VBA A-0001  aaaa B-0002  bbbb の様になって、VBA列のセルをアクティブにするとID列のセルに自動でハイパーリンクが設定される。 そして、リンクをさせたいファイル名が"A-0001 aaaa・・・"となっているので 頭の6文字が合致したら、そのファイルを選択してくれるようにしたいです。 説明が下手で申し訳ありませんが、皆様のお知恵をお貸しください。 出来れば・・・ボタンを押すとリンクが貼ってないIDは、全てリンクがかかるようにもしたいのですが・・・。 欲張りを言って申し訳ありません。 宜しくお願いいたします。

  • エクセルのVBAについて質問です。

    エクセル2003のVBAについて質問です。 複数の検索したい文字列があり、複数の検索対象セルがあります。 セルの文字列が検索文字列のいずれかと一致したセルの背景の色を変えたいです。 よろしくおねがいします。 仕事でマクロを組まなけばならなくなってしまったのですが、 初心者のため検索してみたり調べてみたり、参考にして作ってみたのですがうまくいかないばかりかどんどん解らなくなってしまいました。 どうか助けてください。 sheet1のセルが検索対象 (全セル対象でも大丈夫ですが、検索したいセルはB2→J2、B11→J11、B20→J20の範囲です)、 sheet2のA列に検索したい文字列が入力されています。 この検索したい文字列は今後増えていく可能性があるので、増えた場合にも対応できるようにと考えています。 sheet1(検索対象) あ い う え あ お お sheet2(検索文字列) あ う お け き ↑の様に入力されており、sheet1の「あ」と「う」と「お」のセルの背景を変えたいです。 色を変えたいのはsheet1です。 findメソッドや繰り返し処理などを調べて実践してみたのですが、 いきなりマクロを組めといわれた超初心者には難しく質問しています。 自分でやってみたのですが、 sheet1の最初の「あ」のみが変換され、後に出てくる「あ」が変換されません… どうしたらいいのか…どうすることも出来ず困っております。 すみませんが、どなたか優しい方助けてください。 よろしくおねがいします><

  • エクセルVBAでの質問です。

    エクセルVBAでの質問です。 以下のようなA列にID、B列、C列にそれぞれIDに対応したデータがあります。 A      B      C ID    名前    住所 10000 ~ 39999 IDを10000~19999、20000~29999、30000~39999で分けて別シートに もっていこうと思っています。 自分としては、ID左端の数字をLeft関数を使って何とかしようと思っていましたが、 どうしてもうまくいきません。 何かいい方法はないでしょうか。

  • エクセルVBAでのfor文

    エクセルVBAのfor文についての質問です A列のセルに抽出したタイトルが貼り付けられている状態で、そのA列のセルの名前で新規シートを作りたいのですが ・抽出される数が条件によって違うので、A列のセルの数が固定ではない ・1つの名前につき1つの新規シートの作成で、重複して作らない 重複してしまうとシート数が数百単位になってしまい、メモリ不足になると思うので重複は削除して作りたいのですが、この場合のfor文の宣言はどうなるのでしょうか? 抽出される数が条件に応じて変わるのでいまいち分かりません。 (今までfor文は3や5などの指定数での経験しかありません) どうかお助けください

  • 複数行を一列に表示する場合について(EXCEL VBA +ACCESS)

    お世話になります。 現在EXCEL VBAとACCESSでデータを表示する調査をしております。 以下のように、複数行を一列に表示する場合の実現方法が分からず悩んでおります。(SQLはあまり詳しくありません。) 悩みどころは2点あります。  (1)SQLでどのようにデータを取得すればよいか?   (複数回SQLを発行しなければいけないのか?など)  (2)取得したデータの表示方法   (2次元配列で持たせるのが良いのか?など) どなたかご教示いただけませんでしょうか? よろしくお願い致します。 -------------------------------------- 【環境】  Windows XP  EXCEL2003  Access2000  社員テーブル構成   1.id(key1)  :社員コード   2.code(key2) :言語   3.stutus    :状態(1:習得,2:未修得)  EXCELで以下の表示を実現したいと考えてます。   (1)社員テーブルを読み込み、セルにヘッダー行と明細行を出力する。   (2)ヘッダー行には[code]を重複排除して横一列に表示する。   (3)明細行には[id]毎に出力する。   (4)[status]が"1"なら"○"に"2"なら"×"、それ以外は"-"にする。    ([code]は各idに必ずしも存在しない)  ■テーブルイメージ    id   code  status   00001   VBA  1   00001   CBL  1   00002   VBA  2   00002   JAV  2   00002   RPG  1   00003   PHP  1   00003   CBL  2  ■出力イメージ      VBA  CBL  JAV  RPG  PHP  00001  ○  ○   -   -   -  00002  ×  -   ×   ○   -  00003  -  ×   -   -   ○ --------------------------------------

  • accessのvbaでの質問です。

    クエリやテーブルから全件でわなくて、フォームで検索し引っかかったレコードの分だけエクセルに出力させたいんです。 指定したセルにはこの値。 ってな感じで出力させたいです。 でも、いろいろとがんばって見たんですけど・・・。 どーしても、複数行ってのは無理でした・・・。 複数行だと、検索に引っかかった最後のレコードの情報しかそれぞれのセルに入らず、全部入らなかったんです。 どなたかこれを解決できる方いませんか?

  • エクセルの関数、VBA? に関する質問です

    エクセルの関数、VBA? に関する質問です 添付画像のように、 複数のセルの内容(C列)を一つのセルに改行して 入力する場合(M列)はどのような関数にすればよいのでしょうか。 そもそも関数では実現できないのでしょうか 現状はいったんテキストエディタにコピペした後に 再度それを一つのセルにペーストしています。 何か良い方法があれば、教えて頂けると助かります。 よろしくお願いします。

  • Excel VBA について質問です。

    Excel VBA について質問です。 sheet1に、数字が入力され背景色がついたセルがあります。 sheet2に背景色ごとに1列に並び替えをしたいのですが、どのようにしたらよいでしょうか? まったくの初心者で、どうしたらよいのかわかりません。 よろしくお願いします。 1、sheet1の背景色は、指定されていないため何色か指定できない。 2、セルの範囲も都度違うため、指定できない。 3、sheet2には、色ごとに1列に並べるのみでよい。 上記の内容でご理解いただけるでしょうか? よろしくお願いします。