VBAでエクセルからエクセルへの重複データ削除

このQ&Aのポイント
  • VBAを使用してエクセルからエクセルへのデータ取り込みと重複データの削除方法を教えてください。
  • 現在、エクセルの台帳とシステムから出力するcsvファイルのデータを管理しています。csvファイルのデータを台帳に追加する際、重複するデータを削除したいです。
  • 重複データの判定は、A列の通し番号で行っています。現在の方法では時間がかかっているので、より効率的な方法を教えてください。
回答を見る
  • ベストアンサー

VBA教えてください。重複データの削除

エクセルからエクセルへのデータ取り込み、重複データ削除の方法について、とても時間がかかっており、ご教授いただきたいと思い、質問させていただきます。 よろしくお願い致します。 台帳(エクセル)とシステムから出力するcsvファイル(エクセル)があります。 csvファイル(エクセル)のデータを、台帳(エクセル)で管理します。 ‘csvファイル:商品コード、商品名、注文日、納期、などなどA~AZ列まで、1行目は項目名で、その後、1行1商品で2000行ほどデータがあります。 現在進行形のデータが全て出力されるため、台帳にあるデータと重複するものと、新規データがあり、新規データのみを台帳に追加していきたいです。 重複かどうかの判断は、A列の通し番号で判断しています。 台帳:シート4つで進捗を管理しています。 シート(1);csvファイルからデータを取り込むシート      一度出力データ全てを取り込み(※1)、シート(2)、(3)に重複があるデータを削除します(※2)。 シート(2):(1)から次工程にデータを送ったらこちらに移動(0~500行ほどあります) シート(3):(2)から次工程にデータを送ったらこちらに移動(5000行ほどあります) ※1は3秒ほどで完了するのですが、※2は1分近く時間を要しています。 もう少し短くならないかと思うのですが、いかがでしょうか。よろしくお願い致します。早ければ早いほどいいですが、10秒以内を目標にしています。 今は、csvファイルから全データをエクセルに取り込んでから(3秒ほど)、重複削除していますが、csvファイルから取り込むときに、重複データを取り込まないほうがいいのでしょうか。 現状、このような感じです。 Sub 重複削除() Dim i As Long Application.ScreenUpdating = False Application.Calculation = xlCalculationManual ‘BA列にある重複チェックが2以上のとき、削除 For i = 5000 To 5 Step -1  If Worksheets("(1)").Cells(i, 53).Value > 1 Then Rows(i).Delete End If Next i ‘BA列に重複チェックを再設定 Application.Calculation = xlCalculationAutomatic Cells(5, 1).Select Range("BA5") = "IF(A5="""","""",COUNTIF($A$4:$A5,A5)+COUNTIF((2)!$A:$A,A5)+COUNTIF((3)!$A:$A,A5))" Range("BA5").Select Selection.Copy ‘関数を値へ変換 Range("BA6:BA2000").Select ActiveSheet.Paste Application.CutCopyMode = False ‘行幅を整える Rows("5:5").Select Range(Selection, Selection.End(xlDown)).Select Selection.RowHeight = 15.75 Range("A5").Select Application.ScreenUpdating = True '画面描画を静止 End Sub

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

  • ベストアンサー
  • kkkkkm
  • ベストアンサー率65% (1606/2443)
回答No.8

遅い場合メモリにデータを読み込んで操作するという手もあります。 操作をよく理解できていないのでとんちんかんな動作かもしれませんが たとえば以下のコードでは、多分…きっと「旧データ含む新データ」にあって「旧データA」及び「旧データB」にないものをSheet4に書き出します。それぞれA1:A2000まで検査し、ないもののA列からAZ列までのデータを書き出します。 Sub Test() Dim mData1 As Variant Dim mData2 As Variant Dim mData3 As Variant Dim mRow1 As Long, mRow2 As Long, mRow3 As Long, mCo3 As Long, mRow4 As Long Dim Flg As Boolean Dim NewData(1 To 2000, 1 To 52) As Variant mData1 = Sheets("Sheet1").Range("A1:AZ2000").Value '旧データA mData2 = Sheets("Sheet2").Range("A1:AZ2000").Value '旧データB mData3 = Sheets("Sheet3").Range("A1:AZ2000").Value '旧データ含む新データ mRow4 = 0 For mRow3 = 1 To 2000 Flg = False For mRow1 = 1 To 2000 If mData3(mRow3, 1) = mData1(mRow1, 1) Then Flg = True Exit For End If Next If Flg = False Then For mRow2 = 1 To 2000 If mData3(mRow3, 1) = mData2(mRow2, 1) Then Flg = True Exit For End If Next End If If Flg = False Then mRow4 = mRow4 + 1 For mCo3 = 1 To Columns("AZ:AZ").Column NewData(mRow4, mCo3) = mData3(mRow3, mCo3) Next End If Next Sheets("Sheet4").Range("A1:AZ2000").Value = NewData End Sub

kometoshi555
質問者

お礼

kkkkkm さん とても早く、理想通りに処理できました。 コードも理解できました。 エクセルの可能性を感じるとともに、私のやりたいことをみなさんがいっしょに考えていただたことに感激し、改めて感謝申し上げます。

その他の回答 (8)

  • m3_maki
  • ベストアンサー率64% (295/459)
回答No.9

エラー処理など思い切り手抜きですが高速です。(1秒弱くらい) Option Explicit Sub Sample()  Const staRow = 2  Dim myKey As String  Dim MaxRow As Long  Dim myDic As Object  Dim i As Long  Debug.Print "開始:" & Time$  Set myDic = CreateObject("Scripting.Dictionary")  On Error Resume Next  'シート2をディクショナリに追加  With Worksheets("Sheet2")   MaxRow = .Cells(.Rows.Count, 1).End(xlUp).Row '最終行を取得   For i = staRow To MaxRow    myKey = .Cells(i, 1)    myDic.Add myKey, myKey   Next  End With  'シート3をディクショナリに追加 With Worksheets("Sheet3")   MaxRow = .Cells(.Rows.Count, 1).End(xlUp).Row '最終行を取得   For i = staRow To MaxRow    myKey = .Cells(i, 1)    myDic.Add myKey, myKey   Next  End With  'シート1をディクショナリに追加。削除する行にマーク  With Worksheets("Sheet1")   MaxRow = .Cells(Rows.Count, 1).End(xlUp).Row '最終行を取得   ' シート1 のみデータ開始行が異なる場合は staRow を変更(直接 5 にするとか)   For i = staRow To MaxRow    myKey = .Cells(i, 1)    '登録されていなければ登録    If Not myDic.Exists(myKey) Then     myDic.Add myKey, myKey    Else     .Cells(i, 53) = "!"    End If   Next  End With  Set myDic = Nothing  Columns(53).SpecialCells(xlCellTypeConstants, 23).EntireRow.Delete  Debug.Print "終了:" & Time$ End Sub

kometoshi555
質問者

お礼

3_maki さん とても早い処理で、理想通りの処理ができました。 Dictionaryという技術、教えていただき、ありがとうございます。

  • HohoPapa
  • ベストアンサー率65% (454/690)
回答No.7

No6の差し替えです。 シート1の中で重複があるものを除いていなかったのと 行削除した結果を格納するシートにタイトル行を出力していなかったので 差し替えます。 Sub sample()    Dim SQL As String  Dim cn As Object  Dim rs As Object  Dim RowCntI As Long  Dim RowCntP As Long  Dim shIn As Worksheet  Dim LastRow As Long  Dim tgRange As Range    'ThisWorkbook.Sheets("ログ").Cells(3, 2).Value = Now  Const MaxCol = 52 'シート1のデータ列数     'シート1の中で重複があれば行削除  With ThisWorkbook.Sheets("Sh1")   LastRow = .Cells(Rows.Count, 1).End(xlUp).Row   Set tgRange = Range(.Cells(1, 1), .Cells(LastRow, MaxCol))   tgRange.RemoveDuplicates Columns:=1, Header:=xlYes   'タイトル行を複写   .Rows(1).Copy ThisWorkbook.Sheets("Sh5").Rows(1)  End With    '/////////////////  ' Sh1シートとsh2シートをマッチングして  ' Sh4シートに出力    'SQL全文を組み立て、実行  SQL = "SELECT *" & vbCrLf  SQL = SQL & "FROM [Sh1$A2:AZ50000] A" & vbCrLf  SQL = SQL & "LEFT OUTER JOIN [Sh3$A2:B50000] B" & vbCrLf  SQL = SQL & "ON A.F1 = B.F1" & vbCrLf    Set cn = CreateObject("ADODB.Connection")  Set rs = CreateObject("ADODB.Recordset")  cn.Provider = "Microsoft.ACE.OLEDB.12.0"  cn.Properties("Extended Properties") = "Excel 12.0;HDR=No;IMEX=1"  cn.Open ThisWorkbook.Path & "\" & ThisWorkbook.Name  rs.Open SQL, cn  rs.MoveFirst  RowCntI = 0  RowCntP = 0    Set shIn = ThisWorkbook.Sheets("Sh1")  Do   RowCntI = RowCntI + 1   If rs.EOF = True Then Exit Do   If IsNull(rs.Fields(MaxCol)) = True Then    RowCntP = RowCntP + 1    shIn.Rows(RowCntI + 1).Copy ThisWorkbook.Sheets("Sh4").Rows(RowCntP + 1)   End If   rs.MoveNext  Loop    rs.Close  Set rs = Nothing  cn.Close  Set cn = Nothing    '/////////////////  ' Sh4シートとsh3シートをマッチングして  ' Sh5シートに出力    'SQL全文を組み立て、実行  SQL = "SELECT *" & vbCrLf  SQL = SQL & "FROM [Sh4$A2:AZ50000] A" & vbCrLf  SQL = SQL & "LEFT OUTER JOIN [Sh2$A2:B50000] B" & vbCrLf  SQL = SQL & "ON A.F1 = B.F1" & vbCrLf    Set cn = CreateObject("ADODB.Connection")  Set rs = CreateObject("ADODB.Recordset")  cn.Provider = "Microsoft.ACE.OLEDB.12.0"  cn.Properties("Extended Properties") = "Excel 12.0;HDR=No;IMEX=1"  cn.Open ThisWorkbook.Path & "\" & ThisWorkbook.Name  rs.Open SQL, cn  rs.MoveFirst  RowCntI = 0  RowCntP = 0    Set shIn = ThisWorkbook.Sheets("Sh4")  Do   RowCntI = RowCntI + 1   If rs.EOF = True Then Exit Do   If IsNull(rs.Fields(MaxCol)) = True Then    RowCntP = RowCntP + 1    shIn.Rows(RowCntI + 1).Copy ThisWorkbook.Sheets("Sh5").Rows(RowCntP + 1)   End If   rs.MoveNext  Loop    rs.Close  Set rs = Nothing  cn.Close  Set cn = Nothing  'ThisWorkbook.Sheets("ログ").Cells(4, 2).Value = Now End Sub

kometoshi555
質問者

お礼

HohoPapa さん SQL、作っていただいてありがとうございます。お時間かけていただいたことと、推測致します。 私の知識不足と学習が追い付かず、今後の維持管理が困難であることと、社内で勝手にインストールできないこともあり、現状、SQLを使用することは難しいと判断しました。 同じ部署に詳しい人がいればいいのにと思うのですが、お恥ずかしながら、私が一番詳しい状況です。これから少しずつですが、勉強して、アクセスやSQL等も使いこなせるようになりたいと思います。 この数日、考えまして、RemoveDuplicatesを1回したのちに、他シートからもってきたデータを「1」に変換し、さらにRemoveDuplicatesで消しました。15秒ほどかかるのと、プロの方が見たらびっくりするような処理かと思います(社内SEの人に怒られちゃいそうです)が、現状致し方ないです。 アドバイスいただき、お時間いただき、ありがとうございました。 心から感謝致します。

  • HohoPapa
  • ベストアンサー率65% (454/690)
回答No.6

SQLを持ち出せば、 ハードルが少々上がりますし、制限もありますが 少なくとも私の環境では7~8秒で期待の処理ができます。 1行目がタイトル行 シート1,2,3ともA列が商品コード シート1,2,3ともA,B列の途中に空欄のセルがない という条件でよければ、以下のコードをよかったら試してください。 なお、シート名は シート1:Sh1 シート2:Sh2 シート3:Sh3 作業シート:Sh4 行削除の行われた結果を格納するシート:Sh5です。 Sub sample()    Dim SQL As String  Dim cn As Object  Dim rs As Object  Dim RowCntI As Long  Dim RowCntP As Long  Dim shIn As Worksheet    'ThisWorkbook.Sheets("ログ").Cells(3, 2).Value = Now    '/////////////////  ' Sh1シートとsh2シートをマッチングして  ' Sh4シートに出力    'SQL全文を組み立て、実行  SQL = "SELECT *" & vbCrLf  SQL = SQL & "FROM [Sh1$A2:AZ50000] A" & vbCrLf  SQL = SQL & "LEFT OUTER JOIN [Sh3$A2:B50000] B" & vbCrLf  SQL = SQL & "ON A.F1 = B.F1" & vbCrLf    Set cn = CreateObject("ADODB.Connection")  Set rs = CreateObject("ADODB.Recordset")  cn.Provider = "Microsoft.ACE.OLEDB.12.0"  cn.Properties("Extended Properties") = "Excel 12.0;HDR=No;IMEX=1"  cn.Open ThisWorkbook.Path & "\" & ThisWorkbook.Name  rs.Open SQL, cn  rs.MoveFirst  RowCntI = 0  RowCntP = 0    Set shIn = ThisWorkbook.Sheets("Sh1")  Do   RowCntI = RowCntI + 1   If rs.EOF = True Then Exit Do   If IsNull(rs.Fields(52)) = True Then    RowCntP = RowCntP + 1    shIn.Rows(RowCntI + 1).Copy ThisWorkbook.Sheets("Sh4").Rows(RowCntP + 1)   End If   rs.MoveNext  Loop    rs.Close  Set rs = Nothing  cn.Close  Set cn = Nothing    '/////////////////  ' Sh4シートとsh3シートをマッチングして  ' Sh5シートに出力    'SQL全文を組み立て、実行  SQL = "SELECT *" & vbCrLf  SQL = SQL & "FROM [Sh4$A2:AZ50000] A" & vbCrLf  SQL = SQL & "LEFT OUTER JOIN [Sh2$A2:B50000] B" & vbCrLf  SQL = SQL & "ON A.F1 = B.F1" & vbCrLf    Set cn = CreateObject("ADODB.Connection")  Set rs = CreateObject("ADODB.Recordset")  cn.Provider = "Microsoft.ACE.OLEDB.12.0"  cn.Properties("Extended Properties") = "Excel 12.0;HDR=No;IMEX=1"  cn.Open ThisWorkbook.Path & "\" & ThisWorkbook.Name  rs.Open SQL, cn  rs.MoveFirst  RowCntI = 0  RowCntP = 0    Set shIn = ThisWorkbook.Sheets("Sh4")  Do   RowCntI = RowCntI + 1   If rs.EOF = True Then Exit Do   If IsNull(rs.Fields(52)) = True Then    RowCntP = RowCntP + 1    shIn.Rows(RowCntI + 1).Copy ThisWorkbook.Sheets("Sh5").Rows(RowCntP + 1)   End If   rs.MoveNext  Loop    rs.Close  Set rs = Nothing  cn.Close  Set cn = Nothing  'ThisWorkbook.Sheets("ログ").Cells(4, 2).Value = Now End Sub

  • kkkkkm
  • ベストアンサー率65% (1606/2443)
回答No.5

> シート(1)に(2)、(3)のデータからA列のみをコピーして貼っておき、そこに、csvデータを張り付け、その上で、RemoveDuplicatesを行う。 > 残ったもののなかで、A列以外にも値が入っているのが、新規データなので、ループして、A列のみの行を削除する。 ループで行の削除が時間がかかっているという気もするのですが、データがどのようになっているのか頭悪くて分からないのですが想像だと シート(1)をシート(2)の末尾にすべてコピー、すべての列範囲指定で重複列をA列指定での削除 (シート(1)での新規データ以外は削除され新規データのみコピーしたことになる) シート(2)をシート(3)の末尾にすべてコピー、すべての列範囲指定で重複列をA列指定での削除 (シート(2)での新規データ以外は削除され新規データのみコピーしたことになる) だと駄目なのでしょうか。

kometoshi555
質問者

お礼

「ループで行の削除が時間がかかっているという気もする」というご指摘、そうですね。ここが問題なのを忘れていました。 なかなか文面で伝えるのが難しく、実際のものを見ていただける環境にあればいいのにと、また、kkkkkm さんのような方が社内にいればいいのにほんとうに思うのですが……。 シート(2)、シート(3)は進捗管理で使用しているので、元のデータのまま残したいのです。 この数日、考えまして、ループで削除をやめ、ループで値の置き換えならそんなに時間がかからない(?)ような気がして、RemoveDuplicatesを1回したのちに、他シートからもってきたデータを「1」に変換し、さらにRemoveDuplicatesで消しました。15秒ほどかかるのと、プロの方が見たらびっくりするような処理かと思いますが、現状致し方ないです。 アドバイスいただき、ありがとうございました。

  • HohoPapa
  • ベストアンサー率65% (454/690)
回答No.4

>‘csvファイル:商品コード、商品名、注文日、納期、などなどA~AZ列まで、 >1行目は項目名で、その後、1行1商品で2000行ほどデータがあります。 この記述からデータは2行目から開始しているように思えますが、 >For i = 5000 To 5 Step -1 と >Range("BA5") = >"IF(A5="""","""",COUNTIF($A$4:$A5,A5)+COUNTIF((2)!$A:$A,A5)+COUNTIF((3)!$A:$A,A5))" からは、シート1,2,3とも データは5行目?、4行目?から始まっているように読み取れます。 提示されたコードでは、シート1の52列目に計算式を埋め その計算結果をみて、行削除するかどうか判定しているわけですが むしろ、その判定をVBAで行ったほうが早いと思います。 それでもレコードごとに、重複が見つかるまで総当たりしていますので 10秒を下回れるかどうか怪しいですが よかったら参考に挑戦してみてください。 Sub sample()  Dim LastRow As Long  Dim tgRange As Range  Dim i As Long  Const stRow = 2  'シート1のデータ開始行  Const MaxCol = 51 'シート1のデータ列数  With ThisWorkbook.Sheets(1)     'シート1の中で重複があれば行削除   LastRow = .Cells(Rows.Count, 1).End(xlUp).Row   Set tgRange = Range(.Cells(1, 1), .Cells(LastRow, MaxCol))   tgRange.RemoveDuplicates Columns:=1, Header:=xlYes    'シート2,3に同じ商品コードがあったら行削除   LastRow = .Cells(Rows.Count, 1).End(xlUp).Row   For i = LastRow To stRow Step -1    If isHit(.Cells(i, 1).Value) = True Then     .Rows(i).Delete    End If   Next i     '行高設定   LastRow = .Cells(Rows.Count, 1).End(xlUp).Row   .Range(Rows(2), Rows(LastRow)).RowHeight = 15.75  End With End Sub '//重複かどうかの判定関数 Function isHit(SCode As String) As Boolean  Dim RowCnt As Long  Const stRow2 = 2 'シート2のデータ開始行  Const stRow3 = 2 'シート3のデータ開始行  isHit = False    With ThisWorkbook.Sheets(2)   RowCnt = stRow2   Do    If .Cells(RowCnt, 1).Value = "" Then Exit Do    If .Cells(RowCnt, 1).Value = SCode Then     isHit = True     Exit Function    End If    RowCnt = RowCnt + 1   Loop  End With    With ThisWorkbook.Sheets(3)   RowCnt = stRow3   Do    If .Cells(RowCnt, 1).Value = "" Then Exit Do    If .Cells(RowCnt, 1).Value = SCode Then     isHit = True     Exit Function    End If    RowCnt = RowCnt + 1   Loop  End With End Function

kometoshi555
質問者

お礼

HohoPapa さん ありがとうございます。 詳細に読み解いていただいて、作成いただき、ありがとうございました。 実際に動かしてみて、やりたいことはできました。 最初と最後に画面を止めるコード等を入れたのですが、HohoPapa さんもご指摘の通り、総当たりでデータ数が多いためか、30秒ほどかかってしまいました。 HohoPapa さんや、kkkkkmさんが使っているRemoveDuplicatesが早いように思うので、 シート(1)に(2)、(3)のデータからA列のみをコピーして貼っておき、そこに、csvデータを張り付け、その上で、RemoveDuplicatesを行う。 残ったもののなかで、A列以外にも値が入っているのが、新規データなので、ループして、A列のみの行を削除する。 というのを一度やってみて、時間比較しようと思います。 貼ったり、消したり、時間かかりますでしょうか。 一度試してみます。

  • imogasi
  • ベストアンサー率27% (4737/17068)
回答No.3

質問文の説明がごちゃごちゃして、要点を説明できてないと思う。 まずVBAコードなど掲示する以前の問題と思う。 VBAというよりも、(データ処理の)処理ロジック(処理パターン)を、経験を踏んで、豊富にする、訓練する必要があると思う。 >新規データのみを台帳に追加していきたいです。 やりたいことを、一言で言えば、これだろう。 >標題の、「重複データの削除 」(したい)と銘打つのはピント外れと思う。 どちらかと言えば、「更新」の処理にアラルのだろうと思う。 ーー それには、最低でもMSAccess(アクセス)などの(RDBS)データべーを扱えるものを勉強すべきだ。 他の方法としては、ファイルの結合ロジックを使って(VBAを組んで)やれば、新規かどうか判別できるだろう。  どうしてもDBソフトを使わないなら、新規データとCSVデータを(同じ)キー項目でソートし、Mathingのアルゴリズムで突合し、新規データを見つけることができる。一件ずつ検索では処理時間がかかりすぎるだろうから。 ーー  昔は、マスターデータとトランザクションデータという考え(や処理方法)を叩き込まれたものだが、そういうことをどこかで勉強しましたか(これは、エクセルの使い方などではない分野でしょう)?周りに、大きく、教えてもらえる先輩はいますか。今回コードをコピペして解決しても、いろいろな点で、仕事でデータ処理するのはすぐ別の問題にぶち当たるだろう。

kometoshi555
質問者

お礼

imogasi さん ありがとうございます。 説明がごちゃごちゃしており、申し訳ありません。 できるだけやりたいことの詳細と、今考えていることとを伝えようと思ったのですが……的外れだったようです。 SEの方、ロジカルなところ、日々の生活のなかでも生かせそうで、いいですね。 >新規データとCSVデータを(同じ)キー項目でソートし、Mathingのアルゴリズムで突合し、新規データを見つけることができる これはエクセルでもできるのでしょうか。 >昔は、マスターデータとトランザクションデータという考え(や処理方法)を叩き込まれたものだが、そういうことをどこかで勉強しましたか(これは、エクセルの使い方などではない分野でしょう)?周りに、大きく、教えてもらえる先輩はいますか。 全くの独学で、必要時にネットで調べたり、サイトで質問して教えていただいて、なんとかやっている状態です。マスターデータとトランザクションデータという考えはわかりません。社内にSEが一人いるのですが、200人くらいの社員に対して一人なので、細かいところまで見てもらうことができず、自分でするしかない状況です。 現状、作業に手間がかかり、ミスが頻発するような現状を放っておくこともできず、私のような素人がなんとかしなきゃと取り組んでいます。そうすると、中途半端に楽にはなるのですが、それが本当にいいのか、葛藤もあります。 しばらくは大変だけど、放っておいて、イチからプロに見ていただいたほうが、長期的にはいいのかとも思うのですが、難しい問題だと感じています。

  • kkkkkm
  • ベストアンサー率65% (1606/2443)
回答No.2

エクセルの機能に重複の削除がありますのでそちらのコードをマクロの記録で取得してやってみてはいかがでしょう。 単純なものだとこんな感じのコードになります。 ActiveSheet.Range("$A$5:$A$9").RemoveDuplicates Columns:=1, Header:=xlNo あと、蛇足になりますが、‘行幅を整えるでは、.Selectを省略してもいいと思います。今回の場合では時間とはほとんど関係はないと思いますが。.Selectも多くなると時間に関係してくるとは思います。 Range(Rows("5:5"), Rows("5:5").End(xlDown)).RowHeight = 15.75

kometoshi555
質問者

お礼

kkkkkmさん ありがとうございます。 RemoveDuplicates だとシートをまたいでの設定ができなくて、諦めていたのですが、 シート(1)に(2)、(3)のデータからA列のみをコピーして貼っておき、そこに、csvデータを張り付け、その上で、RemoveDuplicatesを行う。 残ったもののなかで、A列以外にも値が入っているのが、新規データなので、ループして、A列のみの行を削除する。 というのを一度やってみて、時間比較しようと思います。 ‘行幅を整えるところ、さっそく修正しました。 ありがとうございます。

  • bardfish
  • ベストアンサー率28% (5029/17765)
回答No.1

RDBほ併用すると非常に簡単になると思いますよ。 Microsoft SQLServer Expressは無料で利用できます。 で、列の内容が不明なので具体例を示すことが出来ませんが、SQLなら重複業を取り除いたデータの抽出ならSQL文1行で作れるかもしれません。 Transact-SQLを作ってSQLServer内で抽出後のテーブルを作り、そのテーブルをExcelに取り込む・・・私ならその方法を取ります。 Excel VBAでSQLを発行して1行ずつ取り込むという方法でもいいと思います。 Microsoft SQLServer Managment StudioでSQLを実行しても同じことが出来るかもしれませんけど試したことないです。 RDBはインデックスの張り方とSELECT文での抽出条件の書き方次第で抽出完了の時間が大きく変わります。これはAccessでも同じです。 Excelはシートに記入するデータが増えると動作そのものが遅くなってきます。ですがデータベースを使用すれば5000件のデータが500万件になってもフロントエンドとしてのソフトの操作自体に影響はありません。せいぜい同じデータ抽出に時間がかかる程度ですが、それでも非常に高速です。 Excelでデータ処理のプログラムを引き継いでAccessに移植したら処理に必要な時間が5分の1に短縮しました。 プログラムも非常に煩雑で、簡単な仕様変更にもプログラム修正が非常に大変な作り方だったので、要求されるであろう仕様変更(抽出条件の変更、追加)を指示画面で指定できるように改造しました。

kometoshi555
質問者

お礼

bardfish さん ありがとうございます。 RDB、Accessだと楽なのですね。 会社内で、RDB、Accessのインストールに許可をとるのが大変なのと、 エクセルしか使わないようなところなので、今後の使用や、修正などを考えると、導入は難しそうです。 まずはエクセルでできる方法でできるだけ所要時間の削減を図り、新しいもの(アクセス等)を導入するのか、検討したいと思います。 その際はまた教えてください。

関連するQ&A

  • マクロでシート2~6のデータをシート1に転記したい

    マクロでシート2~6のデータをシート1に転記したいです。 シート2~6のデータを シート1に順番に転記したくてマクロの記録を利用して作成しました。 シート2~6は列は同じですが行数は異なります。 また行数は作業の都度異なります。 同じ記述が繰り返されているので もう少し記述が短くできるのではと思うのですが どうすればいいでしょうか? Sub データ更新() 'シート1の前回データをクリア Sheets("シート1").Select Range("A2:Q2").Select Range(Selection, Selection.End(xlDown)).Select Range(Selection, Selection.End(xlDown)).Select Selection.ClearContents Range("A2").Select Sheets("シート1").Select Range("A1").Select Sheets("シート2").Select Range("A1").Select 'ヘッダーも合わせて取得 Range(Selection, Selection.End(xlToRight)).Select Range(Selection, Selection.End(xlDown)).Select Selection.Copy Sheets("シート1").Select ActiveSheet.Paste Application.CutCopyMode = False Selection.End(xlDown).Select Selection.Offset(1, 0).Select Sheets("シート3").Select Range("A2").Select 'データのみ取得 Range(Selection, Selection.End(xlToRight)).Select Range(Selection, Selection.End(xlDown)).Select Selection.Copy Sheets("シート1").Select ActiveSheet.Paste Application.CutCopyMode = False Selection.End(xlDown).Select Selection.Offset(1, 0).Select Sheets("シート4").Select Range("A2").Select Range(Selection, Selection.End(xlToRight)).Select Range(Selection, Selection.End(xlDown)).Select Selection.Copy Sheets("シート1").Select ActiveSheet.Paste Application.CutCopyMode = False Selection.End(xlDown).Select Selection.Offset(1, 0).Select Sheets("シート5").Select Range("A2").Select Range(Selection, Selection.End(xlToRight)).Select Range(Selection, Selection.End(xlDown)).Select Selection.Copy Sheets("シート1").Select ActiveSheet.Paste Application.CutCopyMode = False Selection.End(xlDown).Select Selection.Offset(1, 0).Select Sheets("シート6").Select Range("A2").Select Range(Selection, Selection.End(xlToRight)).Select Range(Selection, Selection.End(xlDown)).Select Selection.Copy Sheets("シート1").Select ActiveSheet.Paste Application.CutCopyMode = False Selection.End(xlDown).Select Selection.Offset(1, 0).Select End Sub

  • オートフィルタで抽出したデータをVBAで貼り付けしたい

    質問させていただきます。 エクセルで仕入帳を作っています。 各取引先ごとに1枚のシートになっているのですが、 該当する月をオートフィルタで抽出して、そのデータを1枚のシートに貼り付けていき、各月ごとにデータをまとめたいと思っています。 ユーザーフォームで月を入力してオートフィルタで抽出しているのですが、データのないシートの場合不要な部分までコピー&ペーストされてしまいます。 これを回避するにはどのようにコードをかけばいいのでしょうか。 よろしくお願い致します。 現在はこのようなコードで抽出しています。 Private Sub CommandButton1_Click() Application.ScreenUpdating = False Worksheets("sheet2").Select Range("H1:H17").Select Range("H17").Activate Selection.AutoFilter Field:=8 Rows("2:2").Select Rows("2:500").Select Selection.ClearContents RowIndex = 3 '行番号の初期値設定 Do While Worksheets("目次").Cells(RowIndex, 1).Value <> "" '拾ったセルの値が空でない間ループ内の処理をする 検索値 = UserForm1.TextBox1.Text DataSheetName = Worksheets("目次").Cells(RowIndex, 1).Value Worksheets(DataSheetName).Select Range("A2").Select Range(Selection, ActiveCell.SpecialCells(xlLastCell)).Select Selection.AutoFilter Selection.AutoFilter Field:=13, Criteria1:=検索値 & "月分" Set tbl = ActiveCell.CurrentRegion tbl.Offset(2, 0).Resize(tbl.Rows.Count - 2, tbl.Columns.Count).Select Selection.Copy Worksheets("sheet2").Select IRow = Range("A" & Rows.Count).End(xlUp).Row Range("A" & IRow + 1).PasteSpecial Paste:=xlPasteValues Application.CutCopyMode = False Worksheets(DataSheetName).Select Selection.AutoFilter Field:=13 RowIndex = RowIndex + 1 '行番号カウントアップ Loop Application.ScreenUpdating = True Worksheets("sheet2").Select Range("A2").Select Unload UserForm1 End Sub

  • エクセルのマクロで各Sheetのデータを複数コピー&ペーストしたいです

    エクセルのマクロで各Sheetのデータを複数コピー&ペーストしたいです 1つのエクセルファイルの中に複数のSheetがあります。 各Sheetの4行目以降(5行目から)にデータのあるA列~O列をコピーしていって、 挿入-ワークシート(Sheet1という名前で構わない)に全てを順番にコピーしていきたいです。 ”新しいマクロの記録”で下記のように作成したのですが、  ・5行目からデータのあるA列~O列をコピーしていく   ・存在する全てのSheetから上記の作業をする というマクロの書き方が分かりません。 恐れ入りますがお時間ある方で上記の内容をご理解頂ける方がいましたらアドバイス頂ければ非常に助かります。 Sub Macro1() Sheets.Add Sheets("ER10(zy)").Select Rows("5:8").Select Selection.Copy Sheets("Sheet1").Select ActiveSheet.Paste Sheets("ER10(cx)").Select Rows("5:9").Select Application.CutCopyMode = False Selection.Copy Sheets("Sheet1").Select Range("A5").Select ActiveSheet.Paste Sheets("ER10(zht)").Select Rows("5:13").Select Application.CutCopyMode = False Selection.Copy Sheets("Sheet1").Select Range("A10").Select ActiveSheet.Paste End Sub

  • エクセルのマクロで各Sheetのデータを複数コピー&ペーストしたいです

    エクセルのマクロで各Sheetのデータを複数コピー&ペーストしたいです 1つのエクセルファイルの中に複数のSheetがあります。 各Sheetの4行目以降(5行目から)にデータのあるA列~O列をコピーしていって、 挿入-ワークシート(Sheet1という名前で構わない)に全てを順番にコピーしていきたいです。 ”新しいマクロの記録”で下記のように作成したのですが、  ・5行目からデータのあるA列~O列をコピーしていく   ・存在する全てのSheetから上記の作業をする というマクロの書き方が分かりません。 恐れ入りますがお時間ある方で上記の内容をご理解頂ける方がいましたらアドバイス頂ければ非常に助かります。 Sub Macro1() Sheets.Add Sheets("ER10(zy)").Select Rows("5:8").Select Selection.Copy Sheets("Sheet1").Select ActiveSheet.Paste Sheets("ER10(cx)").Select Rows("5:9").Select Application.CutCopyMode = False Selection.Copy Sheets("Sheet1").Select Range("A5").Select ActiveSheet.Paste Sheets("ER10(zht)").Select Rows("5:13").Select Application.CutCopyMode = False Selection.Copy Sheets("Sheet1").Select Range("A10").Select ActiveSheet.Paste End Sub

  • excel 2003でCSVファイルを読み込むVBA

    現在CSVファイルを読み込むマクロを作成してますが、レベルが低く下記載のコードで作業を行ってます。 皆様の技術をお借りしたいので、ご教授宜しくお願い致します。 ※現在のコードです。 CommandButton1でフォルダーを開いてcsvファイルを選択し、toolをsheetに追加してます。それから、CommandButton3で追加されたtoolからB14:C14)を選択し最終行までコピーしSheet1の(B12)に数値のみを貼り付けています。 結構手間が係り作業に時間がかかってしまいます。 そこで、改良をしたいと思いますのでご教授お願い致します。 ※改良したいポイント (1)同じフォルダー内のTOOL.CSVをフォルダーを開かず直接commandButton1でSheetに追加する。 (2)Sheet2にコピーされたデーターから(B14:C14)を選択し最終行までコピーしSheet1の(B12)に数値のみを貼り付ける。 (commandButton3はなくしたいと思ってます) 以上です。 宜しくお願い致します。 --------------------------------------------------------- Private Sub CommandButton1_Click() Application.Calculation = xlCalculationManual Application.ScreenUpdating = False Myname = ActiveWorkbook.Name CSV_Filename = Application.GetOpenFilename("CSVファイル(*.CSV;*.prn),*.CSV;*.prn", , "CSVファイルを開く") If CSV_Filename = False Then Exit Sub Workbooks.Open CSV_Filename CSV_SheetName = Worksheets(1).Name Sheets(CSV_SheetName).Move after:=Workbooks(Myname).Sheets(Sheets.Count + 1) Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub ---------------------------------------------------------------- Private Sub CommandButton3_Click() Application.Calculation = xlCalculationManual Application.ScreenUpdating = False Sheets("(TOOL)").Select Sheets("(TOOL)").Range("B14:C14").Select Sheets("(TOOL)").Range(Selection, Selection.End(xlDown)).Select Selection.copy Sheets("CSV Road").Select Sheets("CSV Road").Range("B12").Select Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _ :=False, Transpose:=False Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub -------------------------------------------------------------

  • エクセル2000のVBAで、入力セルのデータを転記したい

    シート1の5行目あたり(例えばBの5)に入力用セルを置き、値を入れてボタンを押したら 11/6の部分にその値が表示されるようにしたい。 同じシート1の10行目に題名を入れている(下記ではABCD・・・の部分) 11行目からデータ内容を下に記載していく。 10    A      B     C       D 11 2007/11/1 $2000 月平均  半月平均 12 2007/11/2 $2300 月平均  半月平均 13 2007/11/3        月平均  半月平均 14 2007/11/4 $2350 月平均  半月平均 15 2007/11/5        月平均  半月平均 16 2007/11/6        月平均  半月平均 このデータは日付A列がもともと入っています。 毎日の為替相場をデータにしていきたいと考えてください。 土日祝日等は入力しませんので、入力しない日(休祝日だった場合)はそのまま空欄に していくと言う形です。11/5が休みだといって11/4の次のセルを11/6にすると言うのではありません。 1年365日あるのでデータとしては日付部分に365行分先に入力されている形です。 Bだけが空欄で、CとDはアベレージ計算式が入っています。 下のマクロを組みましたが、これだと17行目の指定した列から入力されてしまいます。 どのようにしたらいいのか教えていただけますか? 入力セルに日付も必要ですか? Sub ボタン1_Click() Application.ScreenUpdating = False Sheets("シート1").Select Range("B5").Select Selection.Copy Sheets("シート1").Select Range("A65536").Select Selection.End(xlUp).Select Selection.Offset(1, 0).Select Selection.PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:= _ False, Transpose:=True Application.CutCopyMode = Flase Sheets("シート1").Select Range("C10").Select Selection.ClearContents Range("B5").Select End Sub

  • エクセルVBAで教えて下さい。

    A1のセルに [ 1- 5] 4.05398e-01 3.63385e-01 -2.22992e-01 9.89158e-03 -6.43695e-02 A2のセルに [ 6-10] -5.12224e-04 4.07480e-04 -2.73746e-04 -1.77853e-02 -2.13805e-03 A3のセルに [11-15] -6.88489e-03 -2.06765e-02 -9.44633e-03 6.97059e-03 -1.28400e-02 と、このような感じでA7セルまで同じ感じでスペースで空いた数値が入力されています。 A8のセルのみ [36-37] -6.39210e-03 -1.55806e-03 と入力されております。 まず行いたいのはスペースが空いてる部分で、それぞれの数値を各セルに分けたいです。 A1のセルに入力されている [ 1- 5] 4.05398e-01 3.63385e-01 -2.22992e-01 9.89158e-03 -6.43695e-02 ならば A1に[1-5] B1セルに4.05398e-01 C1セルに3.63385e-01 のように これをA1からA8のセルで行ったあと指定のセルを30行目に貼り付けます。 E1→A29 C2→B29 D2→C29 E2→D29 E3→E29 F3→F29 B4→G29 D5→H29 E5→I29 F5→J29 貼り付けのデータは増えていきます。つまり、30行目にデータが入ってる場合は そのデータが1行下の行に下がり、新たなデータが30行目に追加されます。 このようにして、データが最大で58行目まで追加される可能性があります。 最小であれば30行目、31行目の2つしかない場合あります。 この時、0の近似値を各列のセルから探し、当てはまるセルを赤く塗り潰すというのが 今回行いたいことです。 A列ならA30~A58までの中で0の近似値を探し、当てはまるセルを赤く塗り潰す。 ただ空白の場合は無視してもらいたいです。0の近似値だと空白が選択されてしまうので。 近似値探しの前までならマクロがありますのでご参照下さい。 Sub Macro4() ' ' Macro4 Macro ' ' Range("A1:A8").Select Selection.TextToColumns Destination:=Range("A1"), DataType:=xlFixedWidth, _ FieldInfo:=Array(Array(0, 1), Array(7, 1), Array(21, 1), Array(34, 1), Array(47, 1), _ Array(60, 1)), TrailingMinusNumbers:=True Range("A1").Select Range("E1").Select Selection.Copy Range("A29").Select ActiveSheet.Paste Range("C2:E2").Select Application.CutCopyMode = False Selection.Copy Range("B29").Select ActiveSheet.Paste Range("E3:F3").Select Application.CutCopyMode = False Selection.Copy Range("E29").Select ActiveSheet.Paste Range("B4").Select Application.CutCopyMode = False Selection.Copy Range("G29").Select ActiveSheet.Paste Range("D5:F5").Select Application.CutCopyMode = False Selection.Copy Range("H29").Select ActiveSheet.Paste Range("J7").Select Application.CutCopyMode = False Range("A29:K29").Select Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove Range("A29:K29").Select With Selection.Interior .Pattern = xlNone .TintAndShade = 0 .PatternTintAndShade = 0 End With Range("A29").Select Range("A1:F8").Select Selection.ClearContents Range("A1").Select Range("K29").Select With Selection.Interior .Pattern = xlNone .TintAndShade = 0 .PatternTintAndShade = 0 End With Selection.NumberFormatLocal = "G/標準" End Sub わかりずらい質問ですみませんが、ご指導の程 お願い致します。

  • EXCEL VBAの重複行削除について

    EXCEL2010を使用しています。 添付画像の「重複行削除 前」の表を、RemoveDuplicatesで下の様にコードを組んで A列で重複する行を見て重複する行を削除しています。 Public Sub 重複行削除()  With WorkSheets(1)   .Range(.Cells(1, 1), .Cells(8, 3)).RemoveDuplicates _      Columns:=1, Header:=xlYes  End With End Sub すると、日付の新しいデータが削除され、古いデータが残ってしまいます。 (添付画像の「重複行削除 後」) ReniveDuplicates Columns:=Array(1,3) とした場合は、すべてのデータが残ってしまいます。 添付画像の「欲しいデータ」の表の様に、 日付の新しいものを残すように重複行削除は出来ないでしょうか? 詳しい方、どうか教えてください。 よろしくお願いします。

  • EXCELのVBAについて

    マクロのボタンで内容を削除する様に設定した所、 Dim re As Integer Sheets("投入シート").Select re = MsgBox("入力データをクリアします。" & vbCrLf & vbCrLf & "よろしいですか?", vbOKCancel, "クリア確認") If re <> vbCancel Then Sheets("投入シート").Select ActiveSheet.Unprotect Range("a1:c30").Select Selection.Copy Application.CutCopyMode = False Selection.Copy Sheets("work").Select Range("A1").Select ActiveSheet.Paste Sheets("投入シート").Select ActiveSheet.Unprotect Range("c4:c30").Select Selection.ClearContents Range("f31").Select Selection.Copy Range("c9").Select ActiveSheet.Paste Range("f33").Select Selection.Copy Range("c11").Select ActiveSheet.Paste Range("f32").Select Application.CutCopyMode = False Selection.Copy Range("c14").Select ActiveSheet.Paste Range("c4").Select Application.CutCopyMode = False 'ActiveSheet.Protect DrawingObjects:=True, Contents:=True, Scenarios:=True End If Sheets("投入シート").Select Range("c4").Select End Sub この様に入力したのですがセルのC11の計算式だけセル番号が消えてしまいます。 どうしてでしょうか?ご指導をお願いします。

  • ExcelのVBAです。

    先日お答えいただいたVBAなんですが、 Sub Macro1() Sheets("Sheet1").Select Range("A1").Select Range(Selection, Selection.End(xlDown)).Select Selection.Copy Sheets("Sheet3").Select Range("A1").Select ActiveSheet.Paste Selection.End(xlDown).Select Application.CutCopyMode = False Do Selection.Insert Shift:=xlDown Selection.End(xlUp).Select Loop Until ActiveCell.Address = "$A$1" End Sub というのを使用させて頂いてます。 これを、コピー先のものを上書きせずに、コピーされたものがあれば表示させるといった風に出来ないでしょうか? 例  A    A 1 a 1 2 b → 2あ 3 c 3 右から左に一行間隔で別シートに表示させたいのですが、  A  1 a 2 あ 3 b 4 5 b という結果にしたいのです。 拙い文章で申し訳ないのですが、教えて頂きたいです。

専門家に質問してみよう