いつもお世話になっております。
前回質問した際(https://oshiete.goo.ne.jp/qa/10879923.html)
二つのリストを比べて同じもの(完全一致)するものを抽出する方法を伺ったのですが
今度は部分一致するものを行ごと抽出したいです。
連想配列の場合、LIKEで検索すべきまでは分かったのですが上手く動かず
どうにか助けていただけないでしょうか。
excel2007を使用しておりますので
どうぞよろしくお願いします。
SHEET1⇒大元のデータ
SHEET2⇒検索文字
SHEET2のA列には抽出したい項目があります。
そこでSHEET1のC列の中にとSHEET2のA列の文字が含まれているとき、
SHEET3の二行目以降に行ごとデータを抽出できないでしょうか。
SHEET1 (
(A列) (B列) (C列)
種類 産地 入荷予定
ミルクチョコレート フランス 3月(品川)
ビターチョコレート イタリア 1月(横浜)
ビターチョコレート フランス 12月(立川)
ミルクチョコレート ベルギー 1月(横浜)
ミルクチョコレート ベルギー 3月(立川)
SHEET2
店舗(A列)
横浜
品川
SHEET3
(A列) (B列) (C列)
入荷月 種類 産地
1月(横浜) ビターチョコレート イタリア
3月(横浜) ミルクチョコレート ベルギー
3月(品川) ミルクチョコレート フランス
Option Explicit
Public Sub 入荷設定()
Dim row1 As Long
Dim row2 As Long
Dim row3 As Long
Dim maxrow1 As Long
Dim maxrow2 As Long
Dim i As Long
Dim sh1 As Worksheet
Dim sh2 As Worksheet
Dim sh3 As Worksheet
Dim dicT As Object 'Dictionary
Dim Alrow As Object 'ArrayList
Dim key As Variant
Set sh1 = Worksheets("Sheet1")
Set sh2 = Worksheets("Sheet2")
Set sh3 = Worksheets("Sheet3")
Set dicT = CreateObject("Scripting.Dictionary") ' 連想配列の定義
maxrow1 = sh1.Cells(rows.Count, "A").End(xlUp).row 'A列最終行を求める
maxrow2 = sh2.Cells(rows.Count, "A").End(xlUp).row 'A列最終行を求める
sh3.Cells.ClearContents 'Sheet3クリア
sh3.Range("A1:C1").Value = sh2.Range("A1:C1").Value '見出しコピー
'C列を辞書登録(キー:C列の内容 値:行番号)
For row1 = 2 To maxrow1
key = sh1.Cells(row1, "C").Value
If dicT.exists(key) = False Then
Set Alrow = CreateObject("System.Collections.ArrayList") '.NET Frameworkへの参照
Alrow.Add row1
dicT.Add key, Alrow
Else
dicT(key).Add row1
End If
Next
row3 = 2
'Sheet2を参照
For row2 = 2 To maxrow2
key = sh2.Cells(row2, "A").Value
If dicT.Exists(key) Like sh2.Cells(row2, "B").Value Then '※true からLIKEに変更しています
For i = 0 To dicT(key).Count - 1
row1 = dicT(key)(i)
sh3.Cells(row3, "A").Value = key '入荷月
sh3.Cells(row3, "B").Value = sh1.Cells(row1, "A").Value '種類 '※できれば行ごとにしたいです
sh3.Cells(row3, "C").Value = sh1.Cells(row1, "B").Value '産地
row3 = row3 + 1
Next
Else
MsgBox ("Sheet2の" & row2 & "行:[" & key & "]はSheet1になし")
End If
Next
MsgBox ("完了")
End Sub
No.1ベストアンサー
- 回答日時:
こんばんは!
お示しのコードは詳しく見ていません。
こちらで勝手に考えてみました。一例です。
Sub Sample1()
Dim myDic As Object
Dim i As Long, k As Long, lastRow As Long
Dim myStr As String, buf As String, c As Range
Dim wS1 As Worksheet, wS2 As Worksheet
Dim myKey, myR, myAry
Set myDic = CreateObject("Scripting.Dictionary")
Set wS1 = Worksheets("Sheet1")
Set wS2 = Worksheets("Sheet2")
With Worksheets("Sheet3")
lastRow = .Cells(Rows.Count, "A").End(xlUp).Row
If lastRow > 1 Then
Range(.Cells(2, "A"), .Cells(lastRow, "C")).ClearContents
End If
lastRow = wS1.Cells(Rows.Count, "A").End(xlUp).Row
myR = Range(wS1.Cells(2, "A"), wS1.Cells(lastRow, "C"))
For k = 2 To wS2.Cells(Rows.Count, "A").End(xlUp).Row
Set c = wS1.Range("C:C").Find(what:=wS2.Cells(k, "A"), LookIn:=xlValues, lookat:=xlPart)
If Not c Is Nothing Then
For i = 1 To UBound(myR, 1)
If InStr(myR(i, 3), wS2.Cells(k, "A")) > 0 Then
myStr = myR(i, 3) & "_" & myR(i, 1) & "_" & myR(i, 2)
If Not myDic.exists(myStr) Then
myDic.Add myStr, ""
End If
End If
Next i
Else
buf = buf & wS2.Cells(k, "A") & ","
End If
Next k
myKey = myDic.keys
myR = Range(.Cells(2, "A"), .Cells(UBound(myKey) + 2, "C"))
For i = 0 To UBound(myKey)
myAry = Split(myKey(i), "_")
myR(i + 1, 1) = myAry(0)
myR(i + 1, 2) = myAry(1)
myR(i + 1, 3) = myAry(2)
Next i
Range(.Cells(2, "A"), .Cells(UBound(myKey) + 2, "C")) = myR
Set myDic = Nothing
.Activate
End With
If buf <> "" Then
MsgBox Left(buf, Len(buf) - 1) & "のデータなし!"
Else
MsgBox "完了"
End If
End Sub
※ Sheet2の検索データ?の量は極端に多くはありませんよね?
今回、Sheet2のデータは配列に格納していませんので、
極端に多い場合はSheet2のA列も配列に格納した方が良いかもしれません。m(_ _)m
tom04さん
アドバイスありがとうございました。
また、年末年始でPCが触れず、ご連絡が遅くなってしまい申し訳ありません。
tom04さんやいろいろな方にアドバイスをいただき、なんとか道筋が見えてきました。
本当にありがとうございました。
No.13
- 回答日時:
直接の回答以外ばかりだったので質問文に対してだけの回答を。
Sub megu()
Dim objCn As Object
Dim objRS As Object
Dim i As Integer, sh2 As Worksheet
Dim strSQL As String, st As String
Dim r As Range, rr As Range
Set objCn = CreateObject("ADODB.Connection")
With objCn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Properties("Extended Properties") = "Excel 12.0;HDR=YES;"
.Open ThisWorkbook.FullName
.CursorLocation = 3
End With
Set sh2 = Worksheets("Sheet2")
With Worksheets("Sheet3")
Set r = .Range("A2")
.Cells.ClearContents
For Each rr In sh2.Range("A2", sh2.Cells(Rows.Count, 1).End(xlUp))
st = StrConv(rr.Value, vbNarrow)
strSQL = ""
strSQL = strSQL & " SELECT 入荷予定 As 入荷月,種類,産地"
strSQL = strSQL & " FROM [Sheet1$]"
strSQL = strSQL & " WHERE (入荷予定 Like '%(" & st & ")%') Or (入荷予定 Like '" & st & "%')"
Set objRS = CreateObject("ADODB.Recordset")
Set objRS = objCn.Execute(strSQL)
If r.Address(0, 0) = "A2" Then
For i = 0 To objRS.Fields.Count - 1
.Cells(1, i + 1).Value = objRS.Fields(i).Name
Next
End If
r.CopyFromRecordset objRS
Set r = r.Offset(objRS.RecordCount)
objRS.Close
Set objRS = Nothing
Next
End With
objCn.Close
Set objCn = Nothing
Set r = Nothing
End Sub
ちなみにお古のExcel2002で作成した物なので今のExcelでダメだったらごめんなさい。
No.12
- 回答日時:
No.10です。
もうこの質問自体放置でしょうかね?
No.11さんの投稿につきまして。
>No1の方が、このスレッドから離脱されたようなので、代わりに改造しました。
>このような行為がマナー違反かどうかはわかりませんが、快く思われないならお詫びいたします。
特にマナー違反として書いたつもりはありませんのでお詫びに対してはこちらもお詫びいたします。
単に10個弱の質問サイトを10年ちょい見てきた中でそう言った事に遭遇しなかった(たまたま見た質問以外ではあったのかもですが)と、
言うだけの事です。
撤退された方もここのサイトは自身で削除できないためそうされたのでしょう。
『知恵袋』でなら回答を削除する常連の回答者もいますしね。
補足等を受けて「訳わからん」で削除してますが、眺めていた方にとっては「どこが訳わからんのかわからん」とかありますし。
回答内容について信頼を寄せているとの事ですが、個人的には10年ほど前には普通に使われてたし連想配列に更に別の配列を宣言など
搭載メモリが多くなった近年だから気にしないのかな?と私は気になってます。
質問者さんから改造依頼を受けてって事でもありますしフォローは良かったのかも知れませんね。
でもSetステートメントにより宣言された変数の解放がDictionaryだけなのは、やっぱマクロが終了すると全て解放されるからみたいな感じでしょうかね。
VB・VC#とかやっているとExcel操作でアプリは見えなくなってもプロセスでは動いているから解放は注意する癖があるもので。。。
めぐみんさん
何回もアドバイス頂きありがとうございました。
そして、年末年始でPCが触れなくなってしまい、ご連絡が遅くなり本当に申し訳ありません。
自分の不手際と知識不足でご迷惑をかけてしまい、それでもアドバイスをいただけたこと
本当に感謝です。本当にありがとうございました!!
No.11
- 回答日時:
No9です。
本件、質問者への回答ではありませんが、失礼します。
>コードも出たのでこちらからはないですけど、でも他の回答者のコードを改造し載せるのは余り見かけないですね。
>通常は回答された人に不具合発生を報告し当人が対処するもので、仮に当人がお手上げならフォローするのはよく見かけますが。
No1の方が、このスレッドから離脱されたようなので、代わりに改造しました。このような行為がマナー違反かどうかはわかりませんが、快く思われないならお詫びいたします。
No1の方は、ここの常連で、回答自体も自分のPC検証済みのものを提示している方なので、回答の内容は常に信頼がおけるものです。
それにも、関わらず、離脱されたのは、たぶん、質問者の返信の内容にご立腹されたからかと推測します。
まあ、私がNo1のかたなら、同じような処置をしたかも知れませんが・・・・。
只、せっかくの回答をこのまま埋もれされるのも忍びないと思い改造した次第です。
もし、No9のマクロが正しく動作し、望んだ結果が得られたら、ベストアンサーはNo1のかたに差し上げてください。
tatsu99さん
ご対応本当にありがとうございました。
年末年始に入ってしまい、会社のPCに触ることができず時間がたってしまい申し訳ありません。
また、私の無理なお願いで不愉快な思いをさせてしまっていたら本当に申し訳ないです。
正直まだ試すことができていないのですが、ここから先は自分で頑張りたいと思います。
本当に本当に、ありがとうございました。
皆さんをベストアンサーにしたいのですが、ここは言われた通りNo1様にしたいと思います。
でもtatsu99さんには本当に感謝しています。ありがとうございました!!!
No.10
- 回答日時:
No.7です。
通常とイレギュラーな場合に対応させるのなら、そのイレギュラーな情報をありったけ出せば普通『正規表現』で処理できると思いますよ。
コードも出たのでこちらからはないですけど、でも他の回答者のコードを改造し載せるのは余り見かけないですね。
通常は回答された人に不具合発生を報告し当人が対処するもので、仮に当人がお手上げならフォローするのはよく見かけますが。
この辺はサイト内の質問者と回答者だけではなく、回答者間の繋がりが関係するのでしょう。昔は良くあった事ですけど今はなくなったのかな。
私個人はイレギュラーがなければExcelBookへの接続からデータを抽出する『データベースもどき』を考えてましたが、何せ古いExcelしかないので
こちらでは出来たとしても最近のExcelで動くかは検証できないのでやめました。
その方が列数(A~ACでしたっけ)を気にして回答コードの手直しで悩む事もないでしょうし。
あ、ちなみに最初にシート1からシート3への項目抽出順序は同じであり抽出が完了してから必要な項目列をカット&挿入で処理しますね。
ただシート1やシート3の項目行が実は1行目でないとか、セルの結合を使用しているなどあれば上記も無理でしょうけど。
No.9
- 回答日時:
No1の方の改造です。
Sheet1はA列(種類)、B列(産地)、K列(入荷予定)の前提です。
------------------------------------------
Option Explicit
Sub Sample1()
Dim myDic As Object
Dim i As Long, k As Long, lastRow As Long
Dim myStr As String, buf As String, c As Range
Dim wS1 As Worksheet, wS2 As Worksheet
Dim myKey, myR, myAry
Set myDic = CreateObject("Scripting.Dictionary")
Set wS1 = Worksheets("Sheet1")
Set wS2 = Worksheets("Sheet2")
With Worksheets("Sheet3")
lastRow = .Cells(rows.Count, "A").End(xlUp).row
If lastRow > 1 Then
Range(.Cells(2, "A"), .Cells(lastRow, "C")).ClearContents
End If
lastRow = wS1.Cells(rows.Count, "A").End(xlUp).row
myR = Range(wS1.Cells(2, "A"), wS1.Cells(lastRow, "K"))
For k = 2 To wS2.Cells(rows.Count, "A").End(xlUp).row
Set c = wS1.Range("K:K").Find(what:=wS2.Cells(k, "A"), LookIn:=xlValues, lookat:=xlPart)
If Not c Is Nothing Then
For i = 1 To UBound(myR, 1)
If InStr(myR(i, 11), wS2.Cells(k, "A")) > 0 Then
myStr = myR(i, 11) & "_" & myR(i, 1) & "_" & myR(i, 2)
If Not myDic.exists(myStr) Then
myDic.Add myStr, ""
End If
End If
Next i
Else
buf = buf & wS2.Cells(k, "A") & ","
End If
Next k
myKey = myDic.keys
myR = Range(.Cells(2, "A"), .Cells(UBound(myKey) + 2, "C"))
For i = 0 To UBound(myKey)
myAry = Split(myKey(i), "_")
myR(i + 1, 1) = myAry(0)
myR(i + 1, 2) = myAry(1)
myR(i + 1, 3) = myAry(2)
Next i
Range(.Cells(2, "A"), .Cells(UBound(myKey) + 2, "C")) = myR
Set myDic = Nothing
.Activate
End With
If buf <> "" Then
MsgBox Left(buf, Len(buf) - 1) & "のデータなし!"
Else
MsgBox "完了"
End If
End Sub
No.8
- 回答日時:
No6です。
>よろしければ改造したものを提示していただけないでしょうか。
>ちなみに下の質問では入力者が"("が半角、全角だったり、その後に文字が続くこともあります(例 八王子急ぎ(3月)
>そのため抽出したいのはケース1、3の場合になります。
問題点がいくつかあります。
①SHEET1の提示された列と実際の列の違いは
提示した列:A列(種類)、B列(産地)、C列(入荷予定)
実際の列 :A列(種類)、B列(産地)、K列(入荷予定)
で間違いないでしょうか。
この回答をいただいていませんが、これで間違いないですか?
②「そのため抽出したいのはケース1、3の場合になります。」
ということですが、ケース2も抽出してしまいます。
元々の要件が”SHEET1のC列の中にSHEET2のA列の文字が含まれているとき”ということなので、
SHEET2に”王子”と記入され、SHEET1のC列に”3月(八王子)”と記入されていれば、条件が成立します。
これを、成立させたくないのは心情的にわかりますが、人間が判断できることであり、マクロでは判断できません。
従って、①で間違いなく、かつケース2も含まれてよいなら提供可能です。
話は変わりますが、例で提示された
八王子急ぎ(3月)
ですが、今までの例では()内は全て地名でしたが、3月等の月が入る場合もあるのですか。
かならず()内に地名が入り、その地名がSHEET2のA列に記入されるなら、ScriptingDictionaryを使う方法もあります。
以下のOKの例だけで統一可能ならScriptingDictionaryを使う方法が提示可能です。
(ScriptingDictionaryは完全一致の場合のみ使用可能で、部分一致の場合に使用することはできません)
SHEET1のC列がOKの例
3月急ぎ(八王子)
(王子)
(八王子)3月とても急ぎ
SHEET1のC列がNGの例
八王子急ぎ(3月)
八王子急ぎ
八王子
No.7
- 回答日時:
自分の回答は出さずに申し訳ないですが。
ママチャリさんのアイデアでイレギュラーな自体を心配されるなら検索値を
店舗
*(横浜)
*(品川)
などと出来ないでしょうか?
明確に括弧も交えれば似たような地名を抽出してしまう危険は回避できるでしょうし。
後ろ括弧の後ろには文字がなければ * もいらないと思うのですが。
ちょっと考えてみただけで未検証な点はごめんなさい。
No.6
- 回答日時:
>tom04さんありがとうございます。
>実際の元データはA列~AC列まであり
>一万行ぐらいあり、
>実際はK列に検索したい項目があります。
>対して検索項目は多くても200行ぐらいで
>A列にあります。
>なので単純に私の力量不足で応用できないのかもしれません。。。
No1のかたのマクロは、あなたが提示したとおりレイアウトであれば正しく動作することをこちらでも確認しました。
たぶん、No1のかたのマクロの改造に失敗しているかとおもいます。
SHEET1の提示された列と実際の列の違いは
提示した列:A列(種類)、B列(産地)、C列(入荷予定)
実際の列 :A列(種類)、B列(産地)、K列(入荷予定)
で間違いないでしょうか。
もし、そうであれば、それに合わせて、No1のかたのマクロを改造したものを提示することは可能です。
No.5
- 回答日時:
補足要求です。
①SHEET1のC列は、必ず
x月(●●)
のように記述されていること。
●●の両端が()でくくられていること。
②SHEET2のA列の文字●●が、SHEET1の●●に一致すれば、抽出する。
上記の①②の条件で抽出を行うということで良いでしょうか。
あなたが提示された条件では
「SHEET1のC列の中にとSHEET2のA列の文字が含まれているとき」とありますので、
SHEET1のC列が「3月八王子」SHEET2のA列が「八王子」の場合、抽出対象になる。・・・ケース1
SHEET1のC列が「3月(八王子)」SHEET2のA列が「王子」の場合、抽出対象になる。・・・ケース2
SHEET1のC列が「3月(八王子)」SHEET2のA列が「八王子」の場合、抽出対象になる。・・・ケース3
たぶん、ケース2の場合は抽出対象にしたくないはずです。
①②の条件で行う場合は、
ケース1もケース2も抽出対象にはなりませんが、それでよいでしょうか。
(ケース3のみ抽出対象になります)
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) VBAコードが作動せず、どこに問題があるのか教えて下さい。 3 2023/06/13 13:20
- Visual Basic(VBA) VBA 別ブックからの転記の高速化について VBA 別ブックからの転記の高速化についてご教授下さい。 19 2022/07/26 13:07
- Visual Basic(VBA) 【VBA】特定のワードが入っている行全体を塗りつぶしたい 4 2022/04/20 15:22
- Excel(エクセル) VBAの指示の内容 昨日こちらでご教示頂いたのですが初心者な為、一つ一つの指示が何をやっているのかわ 2 2022/10/25 18:08
- Visual Basic(VBA) VBA処理追加 こちらでご教示頂いたのですが回答完了させてしまいましたのでこちらからまた質問させてく 2 2022/10/27 09:57
- Visual Basic(VBA) vba 重複データ合算 5 2023/07/05 18:55
- Visual Basic(VBA) VBAで質問ですが、皆さんはどの様に導き出しているのでしょうか? 6 2022/05/03 21:53
- Visual Basic(VBA) ExcelVBAで、index、match関数を使用して、指定範囲に出力したい 3 2022/10/18 21:53
- Visual Basic(VBA) エクセルVBAについて 8 2022/07/13 22:41
- Visual Basic(VBA) VBA横データを縦にしたいです 2 2023/08/08 19:38
このQ&Aを見た人はこんなQ&Aも見ています
-
プロが教える店舗&オフィスのセキュリティ対策術
中・小規模の店舗やオフィスのセキュリティセキュリティ対策について、プロにどう対策すべきか 何を注意すべきかを教えていただきました!
-
二つのリストを比べて部分一致する際に一致する文字列を抽出するVBA
Visual Basic(VBA)
-
Dictionaryを使い4つの条件の一致で2つの集計列を集計したいのです
Visual Basic(VBA)
-
エクセルマクロで特定の範囲が空白という条件
Excel(エクセル)
-
-
4
複数の条件に合う行番号を取得するには
その他(Microsoft Office)
-
5
EXCEL VBA Dictionaryで複数の値を格納→離れた位置に出力する方法
Excel(エクセル)
関連するカテゴリからQ&Aを探す
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
「B列が日曜の場合」C列に/...
-
PowerPointで表の1つの列だけ...
-
お店に入るために行列に並んで...
-
エクセルで二つの数字の小さい...
-
エクセル(勝手に太字になる)
-
EXCELで 一桁の数値を二桁に
-
エクセルで最初のスペースまで...
-
エクセルで文字が混じった数字...
-
エクセルVBA、別ブックへ転記す...
-
エクセルの項目軸を左寄せにしたい
-
Excelで、A列にある文字がB列...
-
Excel 複数列 A列B列C列一致 D...
-
エクセル:ある時間範囲で在席...
-
エクセルで2列のセルを連続して...
-
ある文字を含む際に、値を返す...
-
50人を数回、グループ分けする...
-
2つのエクセルのデータを同じよ...
-
エクセルで特定の行を削除した...
-
エクセルで勝手に式が設定され...
-
Excelで文字+数字のデータの並...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
エクセルで二つの数字の小さい...
-
PowerPointで表の1つの列だけ...
-
2つのエクセルのデータを同じよ...
-
エクセルで最初のスペースまで...
-
エクセルVBA、別ブックへ転記す...
-
エクセル 文字数 多い順 並...
-
エクセル(勝手に太字になる)
-
VBAで文字列を数値に変換したい
-
エクセルで文字が混じった数字...
-
エクセルの表から正の数、負の...
-
「B列が日曜の場合」C列に/...
-
Excelで半角の文字を含むセルを...
-
エクセルの並び変えで、空白セ...
-
Excel、市から登録している住所...
-
エクセル 同じ値を探して隣の...
-
EXCELで 一桁の数値を二桁に
-
エクセル初心者です 関数の入れ...
-
A列がない・・・A列が非表示に...
-
オートフィルターをかけ、#N/A...
-
エクセルで、列の空欄に隣の列...
おすすめ情報
めぐみんさん
前回はお世話になりました。
いろいろ説明不足で申し訳ありません。
この場合は(立川)とあるものは二つとも転記します。
よろしくお願いします。
tom04さん
アドバイスありがとうございます。
試してみたのですが定義エラーと出てしまい。。。
実際はもっとデータの量が多く、私が上手く扱えていないのかもしれません。。。
tom04さんありがとうございます。
実際の元データはA列~AC列まであり
一万行ぐらいあり、
実際はK列に検索したい項目があります。
対して検索項目は多くても200行ぐらいで
A列にあります。
なので単純に私の力量不足で応用できないのかもしれません。。。
ママチャリさんありがとうございます。
こんな簡単なのがあるのですね。
火曜日に早速試してみようと思います。
風邪を引いてしまい検証が出来ず、
返信が遅くなり大変申し訳ありません。
ママチャリさんとめぐみんさんのアイディアで活用してみたのですが上手くいかず。。。
よろしければ改造したものを提示していただけないでしょうか。
ちなみに下の質問では入力者が"("が半角、全角だったり、その後に文字が続くこともあります(例 八王子急ぎ(3月)
そのため抽出したいのはケース1、3の場合になります。
お手数おかけして申し訳ありませんが
よろしくお願いします。
色々説明足らずにも関わらず丁寧な回答ありがとうございます。
①実際の列 :実際の列 :A列(種類)、B列(産地)、K列(入荷予定)で間違いありません。
②ケース2が含まれてても大丈夫です。
基本的には3月(品川)(月/地名)で入力していますが、イレギュラーが起きた際に任意で入力しているため統一がないのが現状です。
ただ、そういったイレギュラーなものについては省いても仕方ないと思っています。
完全一致よりは部分一致の方が適しているかと思いましたので、よろしくお願い致します。