[[20100329192844]] 『重複データの検索方法を教えていただきたいです』(ゆき夫) ページの最後に飛ぶ

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

 

『重複データの検索方法を教えていただきたいです』(ゆき夫)
 下記の図で重複データのセルの結果を出したいのです。
 A列:商品コード(数字のみ)
 B列:本支店区分(本店=100)
 C,E,G,I,K列:商品名(Null)あり
 D,F,H,J列:他のデータ(今回の処理には使いません)

 ・重複を見る範囲は各商品CD内(A列が同じ)でB列=100以外の行です
 ・各行内における商品の重複は対象外です

    [A]   [B]   [C]  [D]  [E]  [F]  [G]  [H]  [I]
 [1]  商品CD  本支店   商品1 他項目 商品2  他項目 商品3 他項目  結果
 [2]     123     100     ○
 [3]     123      10     △            ×      ○
 [4]     123      35     ×                                         0
 [5]     223     100     △            ○
 [6]     223      22     ○            △
 [7]     223      43     ×
 [8]     223       6     △            ×                           0
 [9]     323     100     ○            ×            △
 [10]    323      32     △            ○
 [11]    323       2     △                                         0
 [12]    423     100     ×            ○
 [13]    423      23     △            ×
 [14]    423      56     ×                                         0
 [15]    423       8     ×                                         0

 言葉にするとこのような処理がしたいです。
 A列が同じコード内でB列が100以外の行同士の商品1と商品2と商品3をみます。
 2行目はB列が100なので対象外です。
 3行目の商品名を3つdictionaryに代入。
 4行目は商品1が既に3行目にあるので結果に0を入力。
 5行目はB列が100なのでdictionaryをクリア
 6行目の商品名を2つdictionaryに代入。
 7行目は6行目には無い商品名なのでdictionaryに代入。
 8行目は既にdictionaryに入っている商品名なので結果に0を入力

 というような処理をしたいのです。
 同じ行内で重複データがあってもそれは対象外で、異なる行同士での重複チェックです。

 お力を貸してください。どうぞよろしくお願いいたします。

 >C,E,G,I,K列:商品名(Null)あり
 と、表とはちゃうみたいですけど(結果表示のI列は商品名が入っているはず)。
 まぁ、とりあえず表のほうが正しいとして。
     (弥太郎)
 '-----------------------------
Sub Yukio()
    Dim dic As Object, i As Long, n As Integer, tbl, x, y
    Set dic = CreateObject("scripting.dictionary")
    tbl = Range("a2").Resize(Range("a" & Rows.Count).End(xlUp).Row - 1, 7)
    ReDim x(1 To UBound(tbl, 1), 1 To 1)
    For i = 2 To UBound(tbl, 1)
        If tbl(i, 2) <> 100 Then
            If Not dic.exists(tbl(i, 1)) Then
                dic(tbl(i, 1)) = Array(tbl(i, 3), tbl(i, 5), tbl(i, 7))
            Else
                y = dic(tbl(i, 1))
                For n = 3 To 7 Step 2
                    If tbl(i, n) <> "" Then
                        If Not IsError(Application.Match(tbl(i, n), y, 0)) And IsEmpty(x(i, 1)) Then
                            x(i, 1) = 0
                        Else
                            ReDim Preserve y(UBound(y) + 1)
                            y(UBound(y)) = tbl(i, n)
                            dic(tbl(i, 1)) = y
                        End If
                    End If
                Next n
            End If
        End If
    Next i
    Range("i2").Resize(UBound(tbl, 1)) = x
End Sub


 数式を使うなら、J列を作業列にして
 J2に =IF(B2=100,"",J1&C2&E2&G2)
 I2に =IF(B2=100,"",IF(ISERROR(FIND(C2,J1))+ISERROR(FIND(E2,J1))+ISERROR(FIND(G2,J1)),"",0))

 J列は100が出てきたらこれまでの商品名をリセットして、& で結合しながら表示。
 I列は、一つ上の行までに 商品名が有ったかどうかを確認しています。

 同じ様な(?)考え方でマクロを作ると。。。
 '------
Sub 商品CD_商品を登録()
    Dim dic As Object, i As Long, ii As Long
    Dim tbl, x
    Set dic = CreateObject("scripting.dictionary")
    tbl = Range("A1").Resize(Range("A" & Rows.Count).End(xlUp).Row, 9).Value
    ReDim x(1 To UBound(tbl, 1), 1 To 1)
    x(1, 1) = tbl(1, 9)
    For i = 2 To UBound(tbl, 1)
        If tbl(i, 2) <> 100 Then
            For ii = 3 To UBound(tbl, 2) - 1 Step 2
                If tbl(i, ii) <> "" Then
                    If dic.exists(tbl(i, 1) & "_" & tbl(i, ii)) Then
                        x(i, 1) = 0
                        Exit For
                    End If
                End If
            Next
            For ii = 3 To UBound(tbl, 2) - 1 Step 2
                If tbl(i, ii) <> "" Then
                    dic(tbl(i, 1) & "_" & tbl(i, ii)) = Empty
                End If
            Next
        End If
    Next
    Range("I1").Resize(UBound(tbl, 1)).Value = x
    Set dic = Nothing
End Sub
 '------

 >For ii = 3 To UBound(tbl, 2) - 1 Step 2
 が二回出ていますが、
  上側がI列に入れた式の様な役割・・・・過去に出てきているか確認
  下側がJ列に入れた式の様な役割・・・・次の行の為に過去に出てきた物を登録
 しています。

 (HANA)

 >弥太郎さん
 どうもありがとうございました!
 関数の入れ子(VBAでも『入れ子』というのでしょうか)がまだ習得できていないので
 とても助かりました。辞書を見ながら解読してみます。

 >HANAさん
 以前にもお世話になりましたが、違う方向からの見方がある事を気づかされます。
 数式もバッチリ結果が出ました。本当に助かります。ありがとうございました!

 教えてください。以前、教えていただいた関数を使用してみました。

 J2に =IF(B2=100,"",J1&C2&E2&G2)
 I2に =IF(B2=100,"",IF(ISERROR(FIND(C2,J1))+ISERROR(FIND(E2,J1))+ISERROR(FIND(G2,J1)),"",0))

 この方法で試したみたところ、一番上の表でセルC15は重複データなのですが、E15に○が入った場合には
 重複データと認識しなくなってしまうのです。
 自分の予想は『整数+#VALUE!』という式になり、答えがエラー値になってしまうため
 重複データではないという結果になってしまうからなのかなと思うのです。
 これを回避する方法は無いかと思い質問いたしました。

 VBAで試しましたが、変数や配列の関数(?)が完全には理解できず、
 会社で使用している表に合わせることができませんでした。

 どうぞよろしくお願いいたします。
(ゆき夫)

 >自分の予想は『整数+#VALUE!』という式になり、答えがエラー値になってしまうため
 >重複データではないという結果になってしまうからなのかなと思うのです。

 確かにそうですね。
 実際は、ISERROR関数に入っているので、FALSE + TRUE + FALSE = 1
 になってしまうため、重複データではないという結果になります。

 現在の方法では、FALSE + FALSE + FALSE = 0 になった時だけ
 ・・・3つのセルの値をそれぞれ J列の中で探した時に
    すべてのセルで値が見つかった場合・・・
 重複データと言う事に成っています。

 少し変更して、
 J2に =IF(B2=100,"★",J1&C2&E2&G2)
 I2に =IF(B2=100,"",IF(ISERROR(1/(FIND(C2,J1)-1))*ISERROR(1/(FIND(E2,J1)-1))*ISERROR(1/(FIND(G2,J1)-1)),"",0))
 としてみるとどうでしょう?

 J2用の式の「★」は、C,E,G列に使われない文字にしてもらえれば何でも良いです。

 最初の式では、検索するセルに入力が無かった場合も、検索値が最初にあった場合も
 FIND関数で調べるとどちらも1に成っていたのを
 未入力なのか、検索値があったのか、検索値がなかったのか
 3つに分けることにしてみました。

 一つだけ取り出すと、数式内の
            __________1
 ISERROR(1/(FIND(C2,J1)-1)) の部分です。
            ~~~~~~~~~~~~~2
         ^^^^^^^^^^^^^^^^3

 FIND(C2,J1) ・・・・・・・・・・・・・・・・・・・・★1★
  C2セルに入力が無い場合   1
  C2セルの値がJ1にある場合 2以上
  C2セルの値がJ1にない場合 #VALUE!

 ★1★−1・・・・・・・・・・・・・・・・・・・・・★2★
  C2セルに入力が無い場合   1−1     =0
  C2セルの値がJ1にある場合 2以上−1 =1以上
  C2セルの値がJ1にない場合 #VALUE!−1=#VALUE

 1/★2★・・・・・・・・・・・・・・・・・・・・・★3★
  C2セルに入力が無い場合   1/0     =#DIV/0!
  C2セルの値がJ1にある場合 1/1以上 =数値
  C2セルの値がJ1にない場合 1/#VALUE!=#VALUE

 ISERROR(★3★)
  C2セルに入力が無い場合   ISERROR(#DIV/0!)=TRUE
  C2セルの値がJ1にある場合 ISERROR(数値)   =FALSE
  C2セルの値がJ1にない場合 ISERROR(#VALUE!)=TRUE

 になるので、3つのセルのうちどこかに一つでもFALSEがあったら
 「重複がある」と判断出来る様になりそうです。

 (HANA)

 HANAさんどうもありがとうございました!
 おかげさまで希望どおりの結果が出ました。

 わかりやすい説明付きで本当に助かりました。
 遅い時間にもかかわらずありがとうございました。
 (ゆき夫)

 コードは、↑で載せた物から考えると
 データがA1セルから入っている事にかわりが無い場合

 x(1, 1) = tbl(1, 9)
   結果を書き出す列がI列 = 9列目

 If tbl(i, 2) <> 100 Then
   本支店コードが入っているのがB列 = 2列目

 For ii = 3 To UBound(tbl, 2) - 1 Step 2
   商品が入っているのが C列 = 3列目から
            Step 2 = 2列おき
     UBound(tbl, 2) - 1 の部分は 直接値を入れると
     今回の場合 H列 = 8列目(或いは G列 = 7列目)
           C列から2列セットで3つあるので、H列までと考える。
       ただ、実際にはH列は確認しないので、G列にしても良い。

 Range("I1").Resize(UBound(tbl, 1)).Value = x
   結果を書き出す先頭セルが I1 セル

 ループ処理は2箇所に有るので、列の移動が有っただけなら
 5行の変更になると思います。

 どの位置に有った物が何処へ行ったのか
 置き換えてもらうと動くかもしれません。

 また、こちらのコードの改造なので
[[20100327135924]] 『同じ商品番号同士の金額を比較するVBA』(ゆき夫)
 ↑で載せた物も、基本的には同じです。
 両方のコードを見比べて、どの列がどの列に移動した時に
 何処がどう変わっているか確認してもらって
 同じように変更してみてもらうと良いかもしれません。

 (HANA)

コメント返信:

[ 一覧(最新更新順) ]


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