【Excel VBA】重複行の削除

このQ&Aのポイント
  • Excel VBAを使用して、重複行を削除し、日付データを1列にまとめる方法について教えてください。
  • 質問者はVBAの知識がなく、既存のコードを使用しても上手くいかなかったようです。
  • 質問者はWindows10とExcel 2016を使用しており、助けを求めています。
回答を見る
  • ベストアンサー

【Excel VBA】重複行の削除

はじめまして。 IDの重複を削除し、日付データを横1列にまとめるVBAについてご教示いただけますと幸いです。 ------------------------------------------------------- ▼シート1(データ入力がされているシート)    A   B   C   D   E   F    1   ID 日付 2  1234  1/1  1/6  1/10  1/20   3  1234  2/3  2/20 4  1234  3/2 5  7777  1/10  1/15  1/20 6  7777  2/2   2/12  2/22 7  9876  2/3 ⇓ マクロ起動後 ▼シート2(重複行を削除しまとめたシート)    A   B   C   D   E   F   G   H 1   ID 日付 2  1234  1/1  1/6  1/10  1/20  2/3  2/20  3/2 3  7777  1/10  1/15  1/20  2/2  2/12  2/22 4  9876  2/3 【補足】 列情報  ・A列…ID  ・B-F列…日付(左詰め) ※日付はIDごと月毎に行が変わるため、IDによって複数行存在する場合があります。 ※A列のIDは重複しない場合もあれば、4行以上ある場合があります。 ※シート1のデータはおおよそ1000-5000行です。 ※IDに対して、日付は5つあれば問題ありません。そのためG列以降の日付を削除しても支障はございません。 ------------------------------------------------------ VBAの知識があまりなく、調べて出てきたものをコピペ使用も試みたのですが、 上手く動かす事ができませんでした…。 お力添え頂けますと幸いです…。 Windows10でエクセル2016を使用しております。 何卒宜しくお願いいたします。

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

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

IDの型が不明なのでVariantにしてます。ID順に並んでいるという考えなので最初にID順に並び替えてます。 Sub Test() Dim Sh1 As Worksheet, Sh2 As Worksheet Dim Sh1LastRow As Long, Sh2LastRow As Long Dim Sh1LastColumn As Long, Sh2LastColumn As Long Dim c As Range, ID As Variant: ID = "" Set Sh1 = Sheets("Sheet1") Set Sh2 = Sheets("Sheet2") Sh1LastRow = Sh1.Cells(Rows.Count, "A").End(xlUp).Row Sh1.Sort.SortFields.Clear Sh1.Sort.SortFields.Add Key:=Range("A2"), _ SortOn:=xlSortOnValues With Sh1.Sort .SetRange Sh1.Range(Sh1.Cells(2, "A"), Sh1.Cells(Sh1LastRow, "G")) .Header = xlNo .Orientation = xlTopToBottom .Apply End With For Each c In Range(Sh1.Cells(2, "A"), Sh1.Cells(Sh1LastRow, "A")) Sh1LastColumn = Sh1.Cells(c.Row, Columns.Count).End(xlToLeft).Column Sh2LastRow = Sh2.Cells(Rows.Count, "A").End(xlUp).Row Sh2LastColumn = Sh2.Cells(Sh2LastRow, Columns.Count).End(xlToLeft).Column If c.Value = ID Then Sh2.Cells(Sh2LastRow, Sh2LastColumn + 1).Resize(1, Sh1LastColumn - 1) = _ Sh1.Range(Sh1.Cells(c.Row, "B"), Sh1.Cells(c.Row, Sh1LastColumn)).Value Else Sh2.Cells(Sh2LastRow + 1, "A").Resize(1, Sh1LastColumn) = _ Sh1.Range(Sh1.Cells(c.Row, "A"), Sh1.Cells(c.Row, Sh1LastColumn)).Value ID = c.Value End If Next Set Sh1 = Nothing Set Sh2 = Nothing End Sub

その他の回答 (8)

  • masnoske
  • ベストアンサー率35% (67/190)
回答No.9

[No.7] です。 セル番地を使わずにレンジだけで処理してみました。 こちらのほうがコードがスッキリしています。 Dim sh1 As Worksheet Dim sh2 As Worksheet Dim rng As Range ' リストの作成元 Dim src As Range ' シート1 のコピー元 Dim dest As Range ' シート2 のコピー先 Dim endCell As Range ' シート2 のコピー終了セル Dim rng1 As Range ' シート1 のA列ループ用 Dim rng2 As Range ' シート2 のA列ループ用 Set sh1 = Sheets("シート1") Set sh2 = Sheets("シート2") ' シート2 の値ををクリアする sh2.Cells.ClearContents ' リスト作成元の範囲を設定する Set rng = Range(sh1.Range("A1"), sh1.Range("A1").End(xlDown)) ' リストを作成する rng.AdvancedFilter Action:=xlFilterCopy, CopyToRange:=sh2.Range("A1"), Unique:=True ' シート2 に一覧を作成する For Each rng2 In Range(sh2.Range("A2"), sh2.Range("A2").End(xlDown)) ' シート2 の A列をループ Set endCell = rng2 For Each rng1 In Range(sh1.Range("A2"), sh1.Range("A2").End(xlDown)) ' シート1 の A列を縦方向にループ If rng1.Value = rng2.Value Then ' コピー Set src = Range(rng1.Offset(0, 1), rng1.End(xlToRight)) Set dest = Range(endCell.Offset(0, 1), endCell.Offset(0, src.Count)) src.Copy dest Set endCell = endCell.Offset(0, src.Count) End If Next Next

mochi123456
質問者

お礼

返答いただき有難うございます! お返事が遅くなってしまい申し訳ありません。 こんなにも短くまとまるものなのですね… 一度導入してみます。ありがとうございました!

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

No2の一部に抜けがありました。動作に問題はないと思いますが念のために訂正部分を Sh1.Sort.SortFields.Add Key:=Range("A2"), _ を Sh1.Sort.SortFields.Add Key:=Sh1.Range("A2"), _ For Each c In Range(Sh1.Cells(2, "A"), Sh1.Cells(Sh1LastRow, "A")) を For Each c In Sh1.Range(Sh1.Cells(2, "A"), Sh1.Cells(Sh1LastRow, "A")) あと、訂正だけではあれですので余計なお世話を… シート2にまとめた後に日付部分が順に並んでいない場合(もとのデータが並んでいなかった場合) 最後にソートするコードを付加します。(データが日付として入っていないと順になりません) For Each c In Sh2.Range(Sh2.Cells(2, "A"), Sh2.Cells(Rows.Count, "A").End(xlUp)) Sh2LastColumn = Sh2.Cells(c.Row, Columns.Count).End(xlToLeft).Column With Sh2.Sort With .SortFields .Clear .Add Key:=Sh2.Cells(c.Row, "B"), SortOn:=xlSortOnValues End With .SetRange Sh2.Range(Sh2.Cells(c.Row, "B"), Sh2.Cells(c.Row, Sh2LastColumn)) .Header = xlNo .Orientation = xlLeftToRight .Apply End With Next また、各行の日付は横方向に順に並んでいるが以下のように行が上下している場合には 2  1234  2/3  2/20 3  1234  1/1  1/6  1/10  1/20   元の最初のソート部分 Sh1.Sort.SortFields.Clear から End With までを以下のように変更すると上記の最後のソートは不要です。 With Sh1.Sort With .SortFields .Clear .Add Key:=Sh1.Range("A2"), SortOn:=xlSortOnValues .Add Key:=Sh1.Range("B2"), SortOn:=xlSortOnValues End With .SetRange Sh1.Range(Sh1.Cells(2, "A"), Sh1.Cells(Sh1LastRow, "Z")) .Header = xlNo .Orientation = xlTopToBottom .Apply End With

  • masnoske
  • ベストアンサー率35% (67/190)
回答No.7

すでにソートされているのなら,処理は簡単です. (1)シート1のA列から重複がないリストをシート2のA列に作る. (2)シート2のA列と同じデータをシート1のA列から探し,見つかったら行の最後までをシート2にコピーする. 以上です. Dim sh1 As Worksheet Dim sh2 As Worksheet Dim rng As Range Dim r1 As Long ' シート1 の行番号 Dim c1 As Long ' シート1 の列番号 Dim r2 As Long ' シート2 の行番号 Dim c2 As Long ' シート2 の列番号 Set sh1 = Sheets("シート1") Set sh2 = Sheets("シート2") ' シート2 の値ををクリアする sh2.Cells.ClearContents ' リスト作成元の範囲を設定する Set rng = Range(sh1.Cells(1, 1), sh1.Cells(1, 1).End(xlDown)) ' リストを作成する rng.AdvancedFilter Action:=xlFilterCopy, CopyToRange:=sh2.Cells(1, 1), Unique:=True ' シート2 に一覧を作成する r1 = 2 r2 = 2 Do While sh2.Cells(r2, 1).Value <> "" ' シート2 の A列をループ c2 = 2 Do While sh1.Cells(r1, 1).Value = sh2.Cells(r2, 1).Value ' シート1 の A列を縦方向にループ c1 = 2 Do While sh1.Cells(r1, c1).Value <> "" ' シート1 の B列から横方向にループ sh2.Cells(r2, c2).Value = sh1.Cells(r1, c1).Value c1 = c1 + 1 c2 = c2 + 1 Loop r1 = r1 + 1 Loop r2 = r2 + 1 Loop

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

Sheet1に元データ Sheet2に結果を入れるとして ーー 前処理として、Sheet1のA列でソートしておく。シートはVBAでも簡単だが、今回は手操作。 キモは、Range( ).End( )の応用問題という感じ。 ーー 標準モジュールに Sub test01() Set sh1 = Worksheets("Sheet1") '原シート Set sh2 = Worksheets("Sheet2") '集約シート lr = sh1.Cells(10000, "A").End(xlUp).Row 'Sh1シートのデータ最下行 'MsgBox lr '-- maekey = sh1.Cells(2, "A") 'Sh1シート第1レコードのキー 第1行目は見出し k = 2 'Sh2シートのk行に集約中、その最初行を2に指定Rick rc1 = sh1.Cells(2, 100).End(xlToLeft).Column sh1.Cells(2, 1).Copy sh2.Cells(2, 1) '集約シートSh2の第2行へ rc2 = sh2.Cells(2, 1000).End(xlToLeft).Column Range(sh1.Cells(2, 2), sh1.Cells(2, rc1)).Copy sh2.Cells(k, rc2 + 1) '-- For i = 3 To lr If sh1.Cells(i, "A") = maekey Then '変わらない場合 rc1 = sh1.Cells(i, 100).End(xlToLeft).Column rc2 = sh2.Cells(k, 1000).End(xlToLeft).Column Range(sh1.Cells(i, 2), sh1.Cells(i, rc1)).Copy sh2.Cells(k, rc2 + 1) Else '変わった k = k + 1 '集約行を1つ下へポイント sh2.Cells(k, 1) = sh1.Cells(i, "A") rc1 = sh1.Cells(i, 100).End(xlToLeft).Column Range(sh1.Cells(i, 2), sh1.Cells(i, rc1)).Copy sh2.Cells(k, 2) End If maekey = sh1.Cells(i, "A") Next i End Sub ーーーー テストデータ Sheet1 ID 日付 1234 1月1日 1月6日 1月10日 1月20日 1234 2月3日 2月20日 1234 3月2日 7777 1月10日 1月15日 1月20日 7777 2月2日 2月12日 2月22日 9876 2月3日 ーー 結果Sheet2 ID 日付 <-手入力 1234 1月1日 1月6日 1月10日 1月20日 2月3日 2月20日 3月2日 7777 1月10日 1月15日 1月20日 2月2日 2月12日 2月22日 9876 2月3日 === 質問の標題の >重複行の削除  は適当では無いと思う(内容を表してない)。 ーー 色々な処理ロジックが考えられるが (1)本回答は、sort後に、前の行と比較法です (2)同じキーをSheet2のA列でFind法なども考えられると思うが。 ーー 書式はあまり考えてない。 コードの中の、列番号の100,100は適当に修正のこと。

mochi123456
質問者

お礼

imogasiさん、ありがとうございます。 何がどのような動きを書いてくださりありがとうございます。 確認してみます! 〉質問の標題の >重複行の削除  は適当では無いと思う(内容を表してない)。 →失礼しました。具体的に何も書かれていませんね…  次回質問する際には細かく書くよう気を付けます。  ご指摘ありがとうございます。

  • masnoske
  • ベストアンサー率35% (67/190)
回答No.5

> VBAの知識があまりなく、調べて出てきたものをコピペ使用も試みたのですが、 VBAの知識がないのは仕方ないですが,あなたは作ったマクロを今後どうしたいのでしょうか. ただ答えが欲しいだけなのか,今後は自分でメンテするのか,今後もメンテをここに依頼するのか.

mochi123456
質問者

補足

今手作業で行っている入力作業や確認作業がとても多く、何とか簡略化できないかな?と 調べた結果、VBA(マクロ?)というものがあることを知りました。 ここで教えていただいた内容をちょっとずつ分解して、 使える範囲を広げられたらと思っています。 なので、現状は答えが欲しいです。 ただ今後メンテもしていきたいし、また躓いてしまったら質問させて頂く事もあるかと思います…。 ハッキリとした回答ができず申し訳ございません。

  • kkkkkm
  • ベストアンサー率65% (1624/2464)
回答No.4

No2です。なんどもすみません。 データが多い場合、画面の表示を止めたほうが早いと思いますので 最初に Application.ScreenUpdating = False 最後に Application.ScreenUpdating = True を追加しておいてください。 なお、データを下方向に追加していますので同じデータで複数回実行すると実行した回数だけデータが下方向に蓄積されていきます。。

mochi123456
質問者

お礼

ありがとうございます! Excelに入れ込み、動かしてみます…! 丁寧に説明いただき、ありがとうございました。

  • kkkkkm
  • ベストアンサー率65% (1624/2464)
回答No.3

No2です。 With Sh1.Sort .SetRange Sh1.Range(Sh1.Cells(2, "A"), Sh1.Cells(Sh1LastRow, "G")) の 最後のGは最後のデータがある可能性のある列まで(たとえばZまで)とか指定してください。右端の列までをシート2に転記しますので並び替えの時に右端まで並び替えていないと結果がおかしくなります。テストでGまでしかデータがなかったのでとりあえずGまでとしたままになりました。

  • masnoske
  • ベストアンサー率35% (67/190)
回答No.1

質問があります。 提示されているデータは縦方向にA列、B列について昇順にソートされています。 次に横方向は左側から順に日付が並んでいます。 この状態からのスタートでしょうか。 あるいは、そもそもバラバラに並んでいるデータで、この順に並べる必要があるのでしょうか。

mochi123456
質問者

補足

masnoskeさん 質問ありがとうございます。 >この状態からのスタートでしょうか。 →おっしゃる通りです。  A列のIDは4~5桁で昇順です。  B列以降は左詰めです。 バラバラに並べられたデータを、一つ前の処理で上記順番に並び替えています。 宜しくお願いいたします。

関連するQ&A

  • Excel VBAで値が重複する行を削除する

    Excel2000を使っています。 シートAに数千件のデータがあります。 シートBのE列にある文字とシートAのD列の文字が重複する場合に、シートAの重複するセルがある行を削除する(且つできれば行のデータを抜き出すVBAを作ろうと考えています。 最近VBAの初心者本をやっと理解したところで、ちんぷんかんぷんとまではいかないけど、知恵熱がでました。 仕事なので自分でなんとかすべきかと思いますが、きっかけの調べ方がまずわからない。 どなたか、解かるきっかけだけでも与えて頂けないでしょうか。とくに、別シートの値と重複する値を探す場合に何をいれるかわかればきっと道は開けると思うんですが…。 初めての質問なので、質問内容が至らなかったらもうしわけありません。

  • VBAで重複していない行を削除したいです。

    初めてgoo質問を使います。 sheet1とsheet2の1列目と2列目で重複していない行を sheet2から削除したいです。 例えば、 Aの列に番号?、Bの列に数字 sheet1 A B CDEF 1 番号A 1 2 番号A 2  3 番号A 3 4 番号C 1 5 番号C 2 6 番号F 6 7 番号F 7 8 番号F 8 9 番号F 9 10 番号F 10 sheet2 A B CDEF 1 番号A 1 2 番号A 2  3 番号A 3 4 番号B 1 5 番号B 2 6 番号B 3 7 番号C 1 8 番号C 2 9 番号D 8 10 番号D 10 があったとして、上記を下記のようにしたいです。 sheet2 A B CDEF 1 番号A 1 2 番号A 2  3 番号A 3 4 番号C 1 5 番号C 2 6 番号F 6 7 番号F 7 8 番号F 8 9 番号F 9 10 番号F 10 CDEFの列にはsheet1とsheet2で違うデータが入っています。 sheet2から重複していない行を削除したいです。 宜しくお願いします。

  • Excel2010で行ごとの重複削除

    Excel2010です。 A行目 1 3 5 5 2 2 3 B行目 2 3 5 5 4 4 C行目 1 9 7 9 9 ↓ A行目 1 3 5 2 B行目 2 3 4 5 C行目 1 7 9 というように、行ごとに重複の削除をしたいと思っています。 データタブに重複の削除があるのですが、列ごとにやるようなので、一度シート全体を 行と列を入れ替えて別シートにコピーして、 1列目全体を選択して、1列目で重複の削除を実行 2列目全体を選択して、2列目で重複の削除を実行 ・・・ というやり方もあるのですが、今扱っているエクセルは197行197列あります。 列選択、重複の削除アイコンをクリックするのを197回繰り返すのは大変です。 自動化する方法はないものでしょうか?

  • エクセルまたはVBAで重複行を削除

    例えば、 A B 1 1 a 2 2 b 3 3 c 4 4 d 5 4 d 6 5 e 7 6 g 8 6 g といった表があるとします。 A列をキーに、昇順にされた一覧表です。 ここで番号が重複している行、この例では4行目と5行目、7行目と8行目がそうです。 こういった重複した行を検索して、行削除したいのですがどんな方法が可能でしょうか? 最終的にはVBAでのイベントになるでしょうが、それ以前にエクセルで前準備などしておくようなことは必要でしょうか? 表自体はかなり膨大な量のデータベースです。 よろしくお願いします。

  • Excel2003での行重複削除

     Excel2003で、列のセル内容が同一の場合を削除・抽出することは可能でしょうか。例えば、次のようなイメージです。 行番号 A列 B列 行1 A1県 B1市 行2 A1県 B2市 行3 A1県 B3市 行4 A1県 B4市 行5 A2県 B5市 行6 A2県 B6市  ここから、A列が同一の行の重複を削除したいのです。上記では、行1から行4までは「A1県」で同一なので、1つの行だけ残し後の行は削除したい。B列の内容は重複削除で一部消えますが構いません。上記の場合、抽出結果は次のようになります(先頭行だけ残した場合ですが)。 行番号 A列 B列 行1 A1県 B1市 行5 A2県 B5市  データベースが大きいため、手作業で削除して行くのは大変です。適当な方法がありましたら、是非、ご教示ください。  どうぞ宜しくお願いします。  

  • 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) とした場合は、すべてのデータが残ってしまいます。 添付画像の「欲しいデータ」の表の様に、 日付の新しいものを残すように重複行削除は出来ないでしょうか? 詳しい方、どうか教えてください。 よろしくお願いします。

  • 重複行を削除

    重複する行をVBAコードで削除したいのですが A列 B列 C列 あ  1  a あ  1  a あ  2  a い  1  a い  2  c い  2  c A列 B列 C列 あ  1  a あ  2  a い  1  a い  2  c のようにABC列同一文字は1行にしたいのですがVBAコード、関数の解る方ご教授願います。

  • エクセルVBAで重複データの削除

    A列、B列、C列・・・とデータが入っていて、B~D列の5行目から10行目が関連の有るデータのかたまりとします。 C~D列の全てのデータが重複している場合に、最初のほうのデータ(行番号が小さいほう)を残すものとして、重複データを削除したいのです。 削除するときは、 B~Dの範囲で削除する。A列等は削除しない。 削除したらデータは上に詰める。 データはソートしない。 ということをやりたいのですが、簡単に出来ますでしょうか? 良く覚えていないのですが、ネット上で色々探してみても、必ずソートしている気がしたので、ソートしない方法が知りたいのですが。

  • EXCEL2000VBAの記述について

    e列~j列の5行目に 下記の項目が入っています。   e列 f列 g列 h列 i列 j列 5行目 4月 5月 6月 7月 8月 9月 別シートのE列の5行目に入っているデータと、上記の列(e列~j列)の5行目に入っているデータが 同じの場合は、別シートのE列の6行目から38行目に入っているデータをコピーして、上記の 同じ項目の場所の6行目から38行目にデータを貼り付けたい場合 VBAで記述の仕方を教えてください。

  • エクセル VBAにて行削除をしたい…

    エクセル2003にて VBA初心者です。 A列1~100に101~200までに番号が振ってあります。 Z列に記入がない場合はその行を削除するVBAを教えてください。 例  A  B  C  D  E  F …… Z 1  101               文字有り 2  102               ブランク 3  103               ブランク 4  104               文字有り 5  105               文字有り … 99  199              文字有り 100  200              ブランク この様な場合2,3,100の行ごと削除をするという形式のものです。 また、この場合A列の番号も自動で変われば(104が102になる等)最高です。 詳しい方教えてください。よろしくお願いします。

専門家に質問してみよう