VBScriptでvlookupのような処理を実施したい
解決済
回答 3
投稿
- 評価
- クリップ 0
- VIEW 2,480
VBSを使用して、VBAで言うVLOOKUPのような処理を実現したいと思っています
(VBAが使用できない理由は、マクロのタスク実行ができない(ログオフ状態で)ためです)
2つのcsvファイルを突き合わせて、指定の共通箇所をもとにファイルの結合をしたいと思っています
共通箇所は以下の通りです
・ファイルAの6カラム目の値
・ファイルBの1カラム目の値
・ファイルA:
AAA,BBB,CCC,DDD,EEE,FFF
SOS1,2019/3/10 10:15,〇,10:05,,1
SOS2,2019/3/10 10:18,〇,00:07,,2
SOS2,2019/3/10 10:11,〇,00:08,,2
SOS2,2019/3/10 10:03,〇,02:01,,2
SOS3,2019/3/10 10:15,〇,00:09,OK1,5
SOS4,2019/3/10 10:19,×,00:04,OK2,6
SOS4,2019/3/10 10:15,×,02:02,OK2,6
・ファイルB:
QQQ,WWW,TTT
1,東京,1位
2,神奈川,2位
3,埼玉,3位
4,千葉,4位
5,秋田,5位
6,青森,6位
⇒結合後は、以下の通りとしたいです
・ファイルC
AAA,BBB,CCC,DDD,EEE,FFF,WWW,TTT
SOS1,2019/3/10 10:15,〇,10:05,,1,東京,1位
SOS2,2019/3/10 10:18,〇,00:07,,2,神奈川,2位
SOS2,2019/3/10 10:11,〇,00:08,,2,神奈川,2位
SOS2,2019/3/10 10:03,〇,02:01,,2,神奈川,2位
SOS3,2019/3/10 10:15,〇,00:09,OK1,5,秋田,5位
SOS4,2019/3/10 10:19,×,00:04,OK2,6,青森,6位
SOS4,2019/3/10 10:15,×,02:02,OK2,6,青森,6位
VBAならば、vlookupでFFFとQQQを突き合せれば何とかなりそうなのですが、
VBSで実現する場合、どのようにすればよいのでしょうか?
お分かりになられる方、
申し訳ございませんがご教授いただけませんでしょうか
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
0
SQLがわかるなら、ADOでCSVファイルに接続してSQLで突き合わせれば一発で希望の結果が取得できます。
参考リンク
ADOを使ってCSVファイルのデータを取得: rururuのブログ
2つのファイルが同じフォルダーにあるなら、ファイル名=テーブル名となりますので、下記のようなSQLをExecuteすればOKです。
SELECT A.*, B.WWW, B.TTT
FROM FileA.csv AS A INNER JOIN FileB.csv AS B ON A.FFF = B.QQQ;
SELECT * INTO
文(テーブル作成クエリ)を使えば、ファイルCへの出力までSQL一発でできますね。
コード書いてみました
Option Explicit
Dim objADO
Dim strPath
strPath = "C:\test\"
Set objADO = CreateObject("ADODB.Connection")
objADO.Open "Driver={Microsoft Text Driver (*.txt; *.csv)};DBQ=" & _
strPath & ";ReadOnly=0"
objADO.Execute "SELECT A.*, B.WWW, B.TTT INTO TableC.csv " & _
"FROM FileA.csv AS A INNER JOIN FileB.csv AS B ON A.FFF = B.QQQ;"
objADO.Close
Set objADO = Nothing
注意点は、
ReadOnly=0
で更新可にすることがポイント。
あと、
ADOドライバーが32Bitだと、32BitのWScriptで実行しないとエラーになります。下記参照。
64bitOS、32bitOffice環境でのWSH\(VBS\)でAccessデータベースに接続する \- hatena chips
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
どちらかのファイル全体を2次元配列変数に記憶します。
他方のファイルを読みながら、変数をループで検索します。
カンマで区切られた文字列を、カンマで分割するにはSplit
関数を使います。
追記
ファイルBの1カラム目が小さい数字(3,4桁くらいまでか)なら、
1次元配列で、1カラム目の数字を添え字にして、そこに、カラム2以降を保存しておけば、
ファイルAを1行読む。
カンマで分割する。
6カラム目を添え字にしてさきほどの配列を参照する。
連結して表示する。
ということで出来るかと思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
ファイルBがマスタファイル的な感じなので、こちらのQQQをキーに連想配列化するのがよろしいかと。
あとはファイルAを読みながらFFFで連想配列を参照して、引っ張ってきたものと一緒にファイルAを出力すればよいですね。
ただファイルBの中身を全部メモリに読み込むことになるので、メモリを圧迫するほどのデータ量だと実用的ではないです。
ざっくりですが、コードを書いてみました。
エラー処理等は省いています。
' ファイルBを連想配列化
Set oFSO = WScript.CreateObject("Scripting.FileSystemObject")
Set oFB = oFSO.OpenTextFile("fileB.csv")
Set dicB = CreateObject("Scripting.Dictionary")
Do While oFB.AtEndOfStream <> True
line = oFB.ReadLine
cols = Split(line, ",")
key = cols(0)
For i = 0 to Ubound(cols) - 2
cols(i) = cols(i+1)
Next
ReDim Preserve cols(Ubound(cols)-2)
cols2 = Join(cols, ",")
dicB.Add key, cols2
Loop
oFB.Close
' ファイルAを読んでファイルCに出力
Set oFA = oFSO.OpenTextFile("fileA.csv")
Set oFC = oFSO.OpenTextFile("fileC.csv")
Do While oFA.AtEndOfStream <> True
line = oFA.ReadLine
cols = Split(line, ",")
outline = line & "," & dicB.Item(cols(5))
oFC.WriteLine outline
Loop
oFA.Close
oFC.Close
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2019/03/20 13:46
ただ、対象機にaccessが入っていないのですが、これは使えるのでしょうか?
2019/03/20 13:50
2019/03/20 14:05
ADODB.Connection
を使用して試してみたいと思います
2019/03/20 18:45
SQLについて質問させてください。
SQLで実現しようとすると、
実際はそのSQLの中にwhere句を入れる想定です。
(csvファイルのうち、指定のカラムに指定の文字列がある行を抽出)
この時、カラム名と指定文字列がともに日本語なのですが、
こちらはシングルクオートでしょうか?ダブルクオートでしょうか?
objADO.Execute "SELECT * INTO fileD.csv " & _
" FROM fileC.csv where 'カラム名' = '指定カラム';"
2019/03/20 19:14 編集
objADO.Execute "SELECT * INTO fileD.csv " & _
" FROM fileC.csv where フィールド名 = '指定文字列';"
フィールド名が日本語でもOKですが、空白や記号が含まれたり、予約語の場合は、[]で囲んでおく必要があります。
objADO.Execute "SELECT * INTO fileD.csv " & _
" FROM fileC.csv where [フィールド名] = '指定文字列';"
下記のリンク先で詳しく説明しています。(VBAですが、VBSも基本同じです。)
https://hatenachips.blog.fc2.com/blog-entry-508.html
2019/03/22 12:18
フィールド名のほうも''で記載いていたためにうまくいかなかったようです
非常に助かりました