人に聞けない痔の悩み、これでスッキリ >>

CSVファイルの内容は、
ID、値1、値2、値3
の4項目だけですが、100万行以上あるため、エクセルのワークシートには取り込めません。
値3には重複している値が多数あって、ユニーク数は40万件ほどになります。
VBAでユニーク数を算出したいだけなのですが可能でしょうか?
重複削除したCSVを生成する必要はありません。
数を出力したいだけです。

ちなみにAccessでリンク取り込みして、値3をグループ化してカウントする方法で実現はしております。
しかし誰でも使えるようにしたいというのと、ExcelVBAでそこまでできるか知りたく質問しました。
あと件数が多いのでできるだけ処理が早く終わる手法だと助かります。
よろしくお願いいたします。

A 回答 (8件)

そのCSVって、「元になる一つ」があって、それを各人ダウンロードしたりしているんですよね?


もしそうなら
・その「元になる一つ」が置いてあるPCで、CSVを作るときに同時に重複を数えるプログラムも実行して、結果を別ファイル(例えばcount.csv)に保存する。
→ 使う人は、Data.csvとcount.csv をダウンロードする

って方法にすれば、「数えるプログラム」は1つのPCで動作させればいいので、「誰でも」である必要はありません。


他にも、Data.csvに保存するのではなく、最初からデータベースサーバーに登録するようにすれば、「SQLの結果だけをExcelに取り込む」ようにVBAでも作れば、「誰でも動かせる」ようになります。


Data.csvを誰でも動かせるプログラムで、ということに固執するのではなく、いろんな方法を考えてみては?
    • good
    • 0

ADO の例です。



Sub Sanple()
 Dim adoCON As Object
 Dim adoRS As Object
 Dim csvDir As String
 Dim strSQL As String

 Set adoCON = CreateObject("ADODB.Connection")
 Set adoRS = CreateObject("ADODB.Recordset")

 csvDir = ThisWorkbook.Path
 strSQL = "Select Count(*) As 件数 From (Select [値3] From Data.csv Group By [値3]) As tbl"

 adoCON.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
    "Data Source=" & csvDir & ";" & _
    "Extended Properties=""Text;" & _
    "HDR=YES;" & _
    "FMT=Delimited"""

 adoRS.Open strSQL, adoCON

 MsgBox adoRS(0) & "件です"

 adoRS.Close
 adoCON.Close
 Set adoRS = Nothing
 Set adoCON = Nothing
End Sub

Excel ファイルと同じフォルダに Data.csv がある場合です。
マシンスペックにもよるでしょうが、3,4秒位で可能です。
    • good
    • 4

>あと件数が多いのでできるだけ処理が早く終わる手法だと助かります。


ならば、ExcelVBAでなく、CやC#で専用のプログラムを作成するのが良い気がします。

>しかし誰でも使えるようにしたい
「当該のCSVファイルをドラッグするだけで答えが表示される」実行形式の専用プログラムを作成すれば良いだけかと・・

私が作るとしたら、
 40万x3程度のハッシュテーブルを用意して、
 未使用の印をつけ、
 CSVファイルを読み込み値3でハッシュテーブルに使用済みの印をつけ、
 読み終わったら、使用済みの印の数を数えて表示する
な感じのプログラムになるかな。メモリ管理が面倒そうなのでC#で作成。
処理内容からして、1,2秒で結果が表示できる程度かなと思います。
    • good
    • 2

No.3です。



『値3』の件数を知りたいだけなら、テキストボックス等に表示させるAccessのフォームを作成してボタンを押して実行の方が楽なのでは?
あとは頻度によりますがCSVファイルをAccessファイルにしてExcelから接続するようにするか。

Accessだと使用者が限られるってのは『Accessが使えない』のか『Accessがインストされてない』のかによりますし。

ネットワークでつながっているなら共有フォルダを作成しておき、変換したAccessファイルに接続するのも手では?
接続者数やネットワーク環境によって時間は変わるかもですけど、ただのテキスト形式の重いファイルで悩むよりかは多少マシな気もしますが。
    • good
    • 0
この回答へのお礼

ありがとうございます。
集計はデイリーです。
あと Accessは全員のPCにはインストールされていません。

お礼日時:2019/08/17 08:20

こんばんは!



A列~D列の重複データが何件存在するか?というコトで良いのですかね。
いずれにしてもExcelで100万行となるときついと思います。
無理やりやってみました。

元データはSheet1にあり1行目は項目行でデータは2行目以降にあり
Sheet2に表示するとします。

Sub Sample1()
 Dim myDic As Object
 Dim i As Long, lastRow As Long
 Dim wS As Worksheet, myStr As String
 Dim myKey, myItem, myR, myAry

  Set myDic = CreateObject("Scripting.Dictionary")
  Set wS = Worksheets("Sheet2")
   wS.Range("A:E").ClearContents
    With Worksheets("Sheet1")
     wS.Range("A1:D1").Value = .Range("A1:D1").Value
     wS.Range("E1") = "件数"
      lastRow = .Cells(Rows.Count, "A").End(xlUp).Row
       myR = Range(.Cells(2, "A"), .Cells(lastRow, "D"))
        For i = 1 To UBound(myR, 1)
         myStr = myR(i, 1) & "_" & myR(i, 2) & "_" & myR(i, 3) & "_" & myR(i, 4)
         If Not myDic.exists(myStr) Then
          myDic.Add myStr, 1
         Else
          myDic(myStr) = myDic(myStr) + 1
         End If
        Next i
    End With
   myKey = myDic.keys
   myItem = myDic.items
    myR = Range(wS.Cells(2, "A"), wS.Cells(UBound(myKey) + 2, "E"))
     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)
       myR(i + 1, 4) = myAry(3)
       myR(i + 1, 5) = myItem(i)
    Next i
    Range(wS.Cells(2, "A"), wS.Cells(UBound(myKey) + 2, "E")) = myR
     Set myDic = Nothing
     wS.Activate
     MsgBox "完了"
End Sub

※ こちらで100万行程度のサンプルでマクロを実行すると
約3分かかってしまいました。m(_ _)m
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
移動中のスマホなので誤解なら申し訳ありませんが、
その内容で言うなら、D列の重複削除後の数が知りたいだけです。A〜C列は無視です。
更に100万行程度じゃないです。
1000万行でも対応可能なロジックじゃないと意味ありません。
すみません。

お礼日時:2019/08/17 01:03

ADOでの件ならExcelからCSVファイルに接続する方法になるので、Excel側の行数は書き出す40万件ほどを気にするだけかと思いますよ。



ただ誰にでも使えるようにって所が何を指しているのかちょっと不明かな?
    • good
    • 0
この回答へのお礼

分かりづらくて済みません。
現場が分からないと伝わらないですね。

Accessを使う方法だと、利用者が限られるのです。
Excel上でボタンをクリックするだけだと環境的にもスキル的にも(こちらの社内では)誰でも集計できるようになるんです。

お礼日時:2019/08/16 22:11

値3の重複しない件数がわかれば良いのですね。


そうであれば、Scripting.Dictionaryを使用するのが簡単かと。
以下の例は、使用例です。
例1
"A", "B", "C", "D", "E", "A", "B", "C"の重複しない件数を出力する。
結果:6
例2
1~1000000の数字の重複しない件数を出力する。
結果:1000000

実際の手順としては
1.CSVファイルを1行読み込み、値3を取得する。
2.値3をキーとしてDictionaryへ登録する。値はtrue固定
3.これを全行分(100万行)、繰り返す。
4.DictionaryのCountプロパティに件数が格納されているので、それを出力する。
ことになるかと。

追伸:例2を実行すると、さすがに重くなりますが、当マシンでは、約30秒で完了しました。
(windows7 メモリ12GB core5 )
10GB以上のメモリを積んでいれば、大丈夫かと思います。
-------------------------------------------
Public Sub sample()
Dim dict As Object
Dim i As Long
Dim val As Variant
Dim key As Variant
val = Array("A", "B", "C", "D", "E", "A", "B", "C")
Set dict = CreateObject("Scripting.Dictionary")
For i = 0 To UBound(val)
key = val(i)
dict(key) = True
Next
Debug.Print dict.Count
dict.RemoveAll '一旦、全てクリアする
For i = 1 To 1000000
dict(i) = True
Next
Debug.Print dict.Count
End Sub
    • good
    • 0

ADOなどで、エクセルに接続して、SQLでselect distinct... がはやいんじゃないかな?


group byもためしてみてもよいけど、、、

https://qiita.com/EmikoKishi/items/7c5e4154cf044 …
    • good
    • 0
この回答へのお礼

VBAから直接CSVを操作しないといけないと思うのですが、
Excelに接続するという事は104万件の壁があるから駄目ではあませんか?
理解が追いついてなかったらすみません。

お礼日時:2019/08/16 14:34

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング