質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.61%

VBScriptでvlookupのような処理を実施したい

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 3,395

score 50

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ページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 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 編集

    VBAのコード内ではSQL文は単なる文字列ですので、SQL文全体は、" で囲みます。SQLではテキストは'でも"でもどちらで囲んでもいいので、' で囲むといいでしょう。カラム名(フィールド名)はテキストではないので ’ で囲んではだめです。
    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

    ありがとうございます。
    フィールド名のほうも''で記載いていたためにうまくいかなかったようです

    非常に助かりました

    キャンセル

0

どちらかのファイル全体を2次元配列変数に記憶します。
他方のファイルを読みながら、変数をループで検索します。

カンマで区切られた文字列を、カンマで分割するにはSplit関数を使います。

追記

ファイルBの1カラム目が小さい数字(3,4桁くらいまでか)なら、
1次元配列で、1カラム目の数字を添え字にして、そこに、カラム2以降を保存しておけば、

ファイルAを1行読む。
カンマで分割する。
6カラム目を添え字にしてさきほどの配列を参照する。
連結して表示する。

ということで出来るかと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/20 11:07

    すいません。
    VBAだと以下のようなコードで作成していたのですが、
    VBSだとどのようなコードになるのでしょうか?

    Const cFormula As String = "=VLOOKUP(@,ーーーー!A:C,3,FALSE)"
    With Worksheets("----")
    Worksheets("利XXXX").Range("A:C").Copy .Range("A:A")
    With .Range("A1").CurrentRegion.Columns(2)
    If Application.CountBlank(.Cells) > 0 Then
    With .SpecialCells(xlCellTypeBlanks)
    .Formula = Replace(cFormula, "@", .Cells(1).Offset(, -1).Address(False, False))
    End With
    .Value = .Value
    End If
    End With
    End With

    キャンセル

  • 2019/03/20 11:10

    回答に書いた通りですが、何が分かりませんか?

    キャンセル

  • 2019/03/20 11:12

    ちょっと追記しておきます。

    キャンセル

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/20 14:07

    だいたい見直し修正しました。

    キャンセル

  • 2019/03/20 18:46

    ありがとうございます。
    希望の操作ができそうですので、
    このコードを勉強させていただきます

    キャンセル

  • 2019/03/20 18:48

    難しいことはやっていないのでがんばってみてください。
    エラー処理とか1行目を読み飛ばす処理とか入れれば結構動くと思いますので。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る