[[20231219144155]] 『表を比較し差分に色付け 追加です』(MMM) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『表を比較し差分に色付け 追加です』(MMM)

以前、下記の条件を元にコードを作成していただきました。
下記内容で作成したいと思っています。

A列(ID)
B列(氏名)

・2つの同一様式のA列(ID)をキーにして比較、B列以降の値が異なるセルに背景色をつける。
・シートはSheet1(比較元)とSheet2(比較先)
・スタート位置はA3セル〜N列、最終行は都度変化、2つのシートの行数も異なる
・Sheet1のZ3セル以降に「○○セルが一致しましせん。Sheet1の値『●』に対し、Sheet2の値『△』です」の差分詳細を表示

更に数点条件を追加したく再度相談させてもらいました。

<追加>
・Sheet1とSheet2のB列(氏名)が違うのに、Sheet1とSheet2のA列(ID)が同じ場合はA列(ID)を赤文字にして「<該当行>のIDが不正です」(複数になる場合あり)のメッセージを出す
・Sheet1とSheet2のA列(ID)が重複していればA列(ID)を赤文字にして「「<該当行>のIDが重複しています」(複数になる場合あり)のメッセージを出す

どうぞよろしくお願い致します。

Sub Sabun2()

    '前提:比較元と比較先の列が同じ
    '変数宣言/設定
    Dim wsMoto As Worksheet, wsSaki As Worksheet 'ワークシート
    Set wsMoto = ThisWorkbook.Worksheets("Sheet1") '比較元ワークシート
    Set wsSaki = ThisWorkbook.Worksheets("Sheet2") '比較先ワークシート
    Dim strCols As String: strCols = "A:N" '指定列範囲(文字列)
    Dim iRow As Long: iRow = 3 '指定範囲開始行番号
    Dim Col As String: Col = "Z" '差分詳細を表示する列
    Dim k As Long: k = 3 '差分詳細の開始行番号
    Dim r As Long: r = wsMoto.Cells(Rows.Count, 1).End(xlUp).Row '処理対象最終行番号(比較元のA列を参照)
    Dim arrMoto As Variant, arrSaki As Variant '配列
    arrMoto = wsMoto.Columns(strCols).Rows(iRow & ":" & r) '比較元範囲
    arrSaki = wsSaki.Columns(strCols).Rows(iRow & ":" & wsSaki.Cells(Rows.Count, 1).End(xlUp).Row) '比較元範囲
    '比較する配列の2次元目を拡張(ID存在チェック用)
    ReDim Preserve arrMoto(LBound(arrMoto, 1) To UBound(arrMoto, 1), LBound(arrMoto, 2) To UBound(arrMoto, 2) + 1)
    ReDim Preserve arrSaki(LBound(arrSaki, 1) To UBound(arrSaki, 1), LBound(arrSaki, 2) To UBound(arrSaki, 2) + 1)
    '表の準備
    wsMoto.Columns(strCols).Rows(iRow & ":" & r).Interior.Pattern = xlNone 'セルの背景色・パターンをクリア
    wsMoto.Range(Col & k & ":" & Col & 100000).ClearContents '差分詳細表示エリアの文字をクリア
    'ループ用変数
    Dim i As Long, j As Long, o As Long
    'Dim n As Long: n = 2 '配列からセル位置にするときに加算する数(指定範囲開始行番号 - 1)
    Dim n As Long: n = iRow - LBound(arrMoto, 1) '配列からセル位置にするときに加算する数
    For i = LBound(arrMoto, 1) To UBound(arrMoto, 1) '比較元行ループ
        For o = LBound(arrSaki, 1) To UBound(arrSaki, 1) '比較先行ループ
            '比較元と比較先のIDが同じ場合
            If arrMoto(i, 1) = arrSaki(o, 1) Then
                'ID存在チェックを入れる
                arrMoto(i, UBound(arrMoto, 2)) = "OK"
                arrSaki(o, UBound(arrSaki, 2)) = "OK"
                For j = LBound(arrMoto, 2) To UBound(arrMoto, 2) '列ループ
                    '比較元と比較先で、同じ列の内容が異なる場合
                    If Not arrMoto(i, j) = arrSaki(o, j) Then
                        '比較元のセルの色を変更
                        wsMoto.Cells(i + 2, j).Interior.Color = 5287936 '緑 =RGB(0,176,80)
                        '詳細表示設定
                        wsMoto.Range(Col & k).Value = wsMoto.Cells(i + n, j).Address _
                        & "が一致しません!" & wsMoto.Name & "シートの値" & arrMoto(i, j) & "に対して" & wsSaki.Name & "シートの値は" & arrSaki(i, j) & "です!"
                        k = k + 1
                    End If
                Next j
            End If
        Next o
    Next i
    'ID存在チェックの結果を確認
    For i = LBound(arrMoto, 1) To UBound(arrMoto, 1) '比較元ループ
        'ID存在チェックが出来ていない場合
        If Not arrMoto(i, UBound(arrMoto, 2)) = "OK" Then
            'A列~N列のセルの色を設定
            wsMoto.Range("A" & i + n & ":N" & i + n).Interior.Color = RGB(255, 128, 128) '赤っぽい色
            '詳細表示設定
            wsMoto.Range(Col & k).Value = "ID" & arrMoto(i, 1) & "が" & wsSaki.Name & "シートに存在しません!"
            k = k + 1
        End If
    Next i
    For o = LBound(arrSaki, 1) To UBound(arrSaki, 1) '比較先ループ
        'ID存在チェックが出来ていない場合
        If Not arrSaki(o, UBound(arrMoto, 2)) = "OK" Then
            '比較元に追記する場合はコメントアウトを解除
' r = r + 1
' For j = LBound(arrSaki, 2) To UBound(arrSaki, 2)
' wsMoto.Cells(r, j).Value = arrSaki(o, j)
' Next j
' 'A列~N列のセルの色を設定
' wsMoto.Range("A" & r & ":N" & r).Interior.Color = RGB(255, 216, 112) '黄色っぽい色
            '詳細表示設定
            wsMoto.Range(Col & k).Value = "ID" & arrSaki(o, 1) & "が" & wsMoto.Name & "シートに存在しません!"
            k = k + 1
        End If
    Next o
End Sub

< 使用 Excel:Microsoft365、使用 OS:Windows11 >


    Sub main()
    Dim c As Range, s1 As Worksheet, s2 As Worksheet, dic1 As Object, dic2 As Object, k, msg As String, i As Long
    Set dic1 = CreateObject("Scripting.Dictionary")
    Set dic2 = CreateObject("Scripting.Dictionary")
    Set s1 = Sheets("Sheet1")
    Set s2 = Sheets("Sheet2")
    s1.Cells.Interior.Color = xlNone
    s2.Cells.Interior.Color = xlNone
    s1.Range("Z:Z").ClearContents
    For Each c In Intersect(s1.UsedRange, s1.Range("A:A"))
        If WorksheetFunction.CountIf(s1.Range("A:A"), c.Value) > 1 Then
            dic1(c.Value) = "ID重複"
        Else
            If c.Value = "" Then
               c.Value = "新規"
            Else
               dic1(c.Value) = WorksheetFunction.TextJoin(Chr(2), False, c.Offset(, 1).Resize(, 13))
            End If
        End If
    Next c
    For Each c In Intersect(s2.UsedRange, s2.Range("A:A"))
        If WorksheetFunction.CountIf(s2.Range("A:A"), c.Value) > 1 Then
          dic1(c.Value) = "ID重複": c.Interior.Color = vbRed
        Else
           dic2(c.Value) = WorksheetFunction.TextJoin(Chr(2), False, c.Offset(, 1).Resize(, 13))
        End If
    Next c
    For Each k In dic1
        msg = "": col = ""
        If dic1(k) = "ID重複" Then
            msg = msg & "ID重複"
        Else
            Select Case dic2(k)
                Case ""
                    msg = "Sheet2にIDなし"
                    dic1(k) = msg
                Case Is <> dic1(k)
                    For i = 0 To UBound(Split(dic2(k), Chr(2)))
                      If Split(dic2(k), Chr(2))(i) <> Split(dic1(k), Chr(2))(i) Then
                        If i > 0 Then
                            msg = msg & "Sheet1の値『" & Split(dic1(k), Chr(2))(i) & "』に対しSheet2の値『" & Split(dic2(k), Chr(2))(i) & "』"
                            col = col & Chr(1) & i
                        Else
                            msg = msg & "ID不正"
                            col = col & Chr(1) & i
                        End If
                      End If
                    Next i
                    dic1(k) = msg & col
            End Select
        End If
        If msg = "" Then dic1(k) = ""
    Next k

    For Each c In Intersect(s1.UsedRange, s1.Range("A:A"))
        If dic1(c.Value) = "ID重複" Then
            c.Interior.Color = vbRed
            c.Offset(, 25).Value = "ID重複"
        ElseIf InStr(dic1(c.Value), "ID不正") > 0 Then
            c.Interior.Color = vbRed
            c.Offset(, 25).Value = "ID不正"
        Else
            If InStr(dic1(c.Value), Chr(1)) > 0 Then
                c.Offset(, 25).Value = Mid(dic1(c.Value), 1, InStr(dic1(c.Value), Chr(1)) - 1)
                For i = 1 To UBound(Split(dic1(c.Value), Chr(1)))
                   c.Offset(, Split(dic1(c.Value), Chr(1))(i) + 1).Interior.Color = vbGreen
                Next i
            Else
                c.Offset(, 25).Value = dic1(c.Value)
            End If
        End If
    Next c
    End Sub

(mm) 2023/12/19(火) 16:41:30


実行しました。
・1行目が赤くなる(3行以降が対象)
・空白の行に「新規」の文字が挿入される

こちらを解消できれば完璧です。
お早い回答を貰えてたすかります。
(MMM) 2023/12/19(火) 16:57:07


失礼しました。
空白の行に「新規」の文字が入るのはA列です。
(MMM) 2023/12/19(火) 16:58:00

すみません、追加で教えていただきたいです。

上記の2点については修正を行いました。

最初の要件で
>・Sheet1とSheet2のB列(氏名)が違うのに、Sheet1とSheet2のA列(ID)が同じ場合はA列(ID)を赤文字にして「<該当行>のIDが不正です」(複数になる場合あり)のメッセージを出す
と記載しておりました。
B列→C列にする場合はどこをどのように修正すればよいのか教えてください。

何度もコードを読もうとしたのですが理解できずにまた頼ってしまいました。
申し訳ございませんがよろしくおねがいします。
(MMM) 2023/12/20(水) 14:16:52


できれば・・・できればのお願いです。

どのコードがどの処理かコメントが頂ければ、大変勉強になります。
(MMM) 2023/12/20(水) 15:26:58


 Sub main()
    ' 変数の宣言
    Dim c As Range, s1 As Worksheet, s2 As Worksheet, dic1 As Object, dic2 As Object, k, msg As String, i As Long

    ' Scripting.Dictionary オブジェクトの作成
    Set dic1 = CreateObject("Scripting.Dictionary")
    Set dic2 = CreateObject("Scripting.Dictionary")

    ' シートの設定
    Set s1 = Sheets("Sheet1")
    Set s2 = Sheets("Sheet2")

    ' シートの背景色をクリア
    s1.Cells.Interior.Color = xlNone
    s2.Cells.Interior.Color = xlNone

    ' シート1の列Zをクリア
    s1.Range("Z:Z").ClearContents

    ' シート1の処理
    For Each c In Intersect(s1.UsedRange, s1.Range("A:A"))
        ' IDの重複をチェック
        If WorksheetFunction.CountIf(s1.Range("A:A"), c.Value) > 1 Then
            dic1(c.Value) = "ID重複"
        Else
            ' IDが空の場合とそれ以外の場合で処理を分岐
            If c.Value = "" Then
                c.Value = "新規"
            Else
                dic1(c.Value) = WorksheetFunction.TextJoin(Chr(2), False, c.Offset(, 1).Resize(, 13))
            End If
        End If
    Next c

    ' シート2の処理
    For Each c In Intersect(s2.UsedRange, s2.Range("A:A"))
        ' IDの重複をチェック
        If WorksheetFunction.CountIf(s2.Range("A:A"), c.Value) > 1 Then
            dic1(c.Value) = "ID重複": c.Interior.Color = vbRed
        Else
            dic2(c.Value) = WorksheetFunction.TextJoin(Chr(2), False, c.Offset(, 1).Resize(, 13))
        End If
    Next c

    ' Dictionary1の各要素に対して比較とメッセージの設定
    For Each k In dic1
        msg = "": col = ""
        If dic1(k) = "ID重複" Then
            msg = msg & "ID重複"
        Else
            Select Case dic2(k)
                Case ""
                    msg = "Sheet2にIDなし"
                    dic1(k) = msg
                Case Is <> dic1(k)
                    ' シート1とシート2の値を比較し、差異があればメッセージを設定
                    For i = 0 To UBound(Split(dic2(k), Chr(2)))
                        If Split(dic2(k), Chr(2))(i) <> Split(dic1(k), Chr(2))(i) Then
                            If i > 0 Then
                                msg = msg & "Sheet1の値『" & Split(dic1(k), Chr(2))(i) & "』に対しSheet2の値『" & Split(dic2(k), Chr(2))(i) & "』"
                                col = col & Chr(1) & i
                            Else
                                msg = msg & "ID不正"
                                col = col & Chr(1) & i
                            End If
                        End If
                    Next i
                    dic1(k) = msg & col
            End Select
        End If
        ' 空の場合はメッセージをクリア
        If msg = "" Then dic1(k) = ""
    Next k

    ' 結果の表示と背景色の設定
    For Each c In Intersect(s1.UsedRange, s1.Range("A:A"))
        If dic1(c.Value) = "ID重複" Then
            c.Interior.Color = vbRed
            c.Offset(, 25).Value = "ID重複"
        ElseIf InStr(dic1(c.Value), "ID不正") > 0 Then
            c.Interior.Color = vbRed
            c.Offset(, 25).Value = "ID不正"
        Else
            If InStr(dic1(c.Value), Chr(1)) > 0 Then
                ' カラムの位置情報を取得し、表示および背景色の設定
                c.Offset(, 25).Value = Mid(dic1(c.Value), 1, InStr(dic1(c.Value), Chr(1)) - 1)
                For i = 1 To UBound(Split(dic1(c.Value), Chr(1)))
                    c.Offset(, Split(dic1(c.Value), Chr(1))(i) + 1).Interior.Color = vbGreen
                Next i
            Else
                ' 差異がない場合はメッセージを表示
                c.Offset(, 25).Value = dic1(c.Value)
            End If
        End If
    Next c
End Sub

(取り急ぎ) 2023/12/20(水) 15:33:44


早く対応して頂きましてありがとうございます。
確認させていただきます。

心より感謝します。
(MMM) 2023/12/20(水) 15:49:37


教えていただけますでしょうか?↑に記しています、「B列→C列に変更する場合」は下記コードの2→3に変更すればよろしいのでしょうか。

For i = 0 To UBound(Split(dic2(k), Chr(2)))

	If Split(dic2(k), Chr(2))(i) <> Split(dic1(k), Chr(2))(i) Then
    	if i > 0 Then
    		msg = msg & "今年度結果の値『" & Split(dic1(k), Chr(2))(i) & "』に対し前年度結果の値『" & Split(dic2(k), Chr(2))(i) & "』"
			col = col & Chr(1) & i
		Else
			msg = msg & "ID不正"
			col = col & Chr(1) & i
		End If
	End If
Next i

(MMM) 2023/12/20(水) 16:08:25


 Chr(2)は区切り文字なので、2は関係ありません。

 dic1(c.Value) = WorksheetFunction.TextJoin(Chr(2), False, c.Offset(, 1).Resize(, 13))
 dic2(c.Value) = WorksheetFunction.TextJoin(Chr(2), False, c.Offset(, 1).Resize(, 13))

 この辺りのc.Offset(,1)の1を2にするのかなとは思いますが、全体の整合性までは見ていません。
(ゆたか) 2023/12/20(水) 16:37:11

ゆたかさんありがとうございます。
2に変更したところ、意図するエラー表示になってくれました。

Chr(2)、質問した後に更に調べたところ全く関係のないコード部分と知りました。
無知でお恥ずかしいです。
(MMM) 2023/12/20(水) 16:51:32


おはようございます。
何度も出てきてしまって申し訳ございません。

 dic1(c.Value) = WorksheetFunction.TextJoin(Chr(2), False, c.Offset(, 1).Resize(, 13))
 dic2(c.Value) = WorksheetFunction.TextJoin(Chr(2), False, c.Offset(, 1).Resize(, 13))

c.Offset(,1)の1を2に変えたところ、他のチェック列がずれるようになってしまいました。

誤)Sheet1とSheet2のB列(氏名)が違う場合、Sheet1とSheet2のA列(ID)が同じ場合はA列(ID)を赤文字にして「<該当行>のIDが不正です」(複数になる場合あり)のメッセージを出す

正)誤)Sheet1とSheet2のC列(氏名)が違う場合、Sheet1とSheet2のA列(ID)が同じ場合はA列(ID)を赤文字にして「<該当行>のIDが不正です」(複数になる場合あり)のメッセージを出す

に修正する場合を教えてもらえますでしょうか。よろしくお願いします。
(MMM) 2023/12/21(木) 09:17:07


If i > 0 Then

If i <> 1 Then
でどう?
(む) 2023/12/21(木) 10:47:47

むさん、ありがとうございます。
このように回答してくださる方たちを尊敬します。

まだまだ無知ですが、しっかり勉強していきたいと思います。
ご回答いただいたみなさま、ありがとうございました。
(MMM) 2023/12/21(木) 10:58:57


 緑色がずれるってことでしょうか?

 c.Offset(, Split(dic1(c.Value), Chr(1))(i) + 1).Interior.Color = vbGreen

 これを

 c.Offset(, Split(dic1(c.Value), Chr(1))(i) + 2).Interior.Color = vbGreen

 でどうでしょうか?

 また、動いているなら良いとも言えますが、

 Dim c As Range, s1 As Worksheet, s2 As Worksheet, dic1 As Object, dic2 As Object, k, msg As String, i As Long

 ではcolが定義されていないので、

 Dim c As Range, s1 As Worksheet, s2 As Worksheet, dic1 As Object, dic2 As Object, k, msg As String, col As String, i As Long
(ゆたか) 2023/12/21(木) 11:30:42

 解決したならそう明記したほうがいいですよ。
[[20231215092241]]
 のように、これから動かしてみます、で返事したことにして、
 結果報告もテキトーな人だから仕方がないけど。
(xyz) 2023/12/21(木) 11:47:20

きちんとした報告とお礼を申し上げずに大変申し訳ありません。
適当な気持ちでお教えいただいていたわけではございませんが、不愉快にさせてしまったこと反省いたします。

ゆたかさん、ありがとうございます。頂いた内容ではやはり緑がずれてしまいました。
むさんの内容では正しく動きました。

頂いたコードで試験しており、解決まで行き届かずご報告できておりませんでした。
長々とお教えいただいたのに、失礼をお許しください。
ありがとうございました。
(MMM) 2023/12/21(木) 16:30:29


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.