2010年4月25日日曜日

第143回目 ユーザー関数(条件付SUMPRO関数、その2)

○第143回目 ユーザー関数(条件付SUMPRO関数、その2)
 
 マクロの中での記述
 a = 条件付SUMPRO_02("D20,A42,A20,42,B20,C21")
または、
 a = 条件付SUMPRO_02(D18) ‘D18には、D20,A42,A20,42,B20,C21が入っている。
 
 先頭行、末尾行の記述
Function 条件付SUMPRO_02(ByVal NN) As Double
 【中味】
End Function

 中味の記述
 
 パラメータ='D20,A42,A20,42,B20,C21
 まずはパラメータの説明です。

 D20…セルの座標です
 A42…セルの座標です。場合によっては数値が入ってきます
 A20…セルの座標です
 42…行数です
 B20…セルの座標です
 C21…セルの座標です。省略された場合は、機能的には、B列に対するSUM関数となります。

 D20のセルにある年齢から
 A42のセルにある年齢までについて
 B20からはじまる項目と
 C21からはじまる項目とを掛け合わせた総和を求める。
 (参照すべき基準年齢は、A20からA42にはいっている)

 Range().Selectが使えませんので、違う方法で列・行を求めます。
 流れです。
 1.パラメータを分解します(mm(i))
 2.座標の場合、それぞれの項目から、列・行を求めます(mm_retu(i)、mm_gyo(i))
 3.列記号は列番号に変換します。(mm_retu(i)の置き換え)
 4.数値情報の場合、セルの内容を求めます(XX,XX9)
 5.積和をとる範囲(最初と最後の行数)を求めます(gyo91、gyo99)
 6.関数式を作ります

 1.パラメータを分解します(mm(i))
 nn0 = NN
 for i = 1 to 5
  p1 = InStr(NN, ",")
  mm(i) = Left(NN, p1 - 1)
  NN = Mid(NN, p1 + 1)
 next
 mm(6) = NN
 If mm(6) = "" Then flag1 = 1

 2.座標の場合、それぞれの項目から、列・行を求めます(mm_retu(i)、mm_gyo(i))
 ii0 = 6
 If flag1 = 1 Then
  ii0 = 5
  mm_retu(6) = ""
  mm_gyo(6) = ""
 End If
 For i = 1 To ii0
  mm(i) = UCase(mm(i))
  If Left(mm(i), 1) Like "[0-9]" = True Then '一桁目が数字
   mm_retu(i) = ""
   mm_gyo(i) = Val(mm(i))
  ElseIf Mid(mm(i), 2, 1) Like "[A-Z]" = True Then '二桁目が英字
   mm_retu(i) = Left(mm(i), 2)
   mm_gyo(i) = Mid(mm(i), 3)
  Else '二桁目が数字
   mm_retu(i) = Left(mm(i), 1)
   mm_gyo(i) = Mid(mm(i), 2)
  End If
 Next i

 3.列記号は列番号に変換します。(mm_retu(i)の置き換え)
  省略
 4.数値情報の場合、セルの内容を求めます(XX,XX9)
  変数を数値に置換えて、通常の変数名の変数に入れる
 パラメータ='D20,A42,A20,42,B20,C21
  retu00 = Val(mm_retu(1)) 集計したい最初の参照値が入っているセルの列番号
  gyo00 = Val(mm_gyo(1))  集計したい最初の参照値が入っているセルの行番号
  retu09 = Val(mm_retu(2)) 集計したい最後の参照値が入っているセルの列番号 数値で入っていた場合、ここが0になります
  gyo09 = Val(mm_gyo(2))  集計したい最後の参照値が入っているセルの行番号
  retu11 = Val(mm_retu(3)) 集計の参照となる先頭セルの列番号
  gyo11 = Val(mm_gyo(3))  集計の参照となる先頭セルの行番号
  retu19 = retu11      集計の参照となる最後セルの列番号
  gyo19 = Val(mm_gyo(4))  集計の参照となる最後セルの行番号
  retu21 = Val(mm_retu(5)) 集計項目1の先頭セルの列番号
  gyo21 = Val(mm_gyo(5))  集計項目1の先頭セルの行番号
  retu31 = Val(mm_retu(6)) 集計項目2の先頭セルの列番号
  gyo31 = Val(mm_gyo(6))  集計項目2の先頭セルの行番号
  gyo_cnt1 = gyo19 - gyo11 + 1 集計する項目数

  XX = Cells(gyo00, retu00) 集計したい最初の参照値
  If retu09 = 0 Then
   XX9 = gyo09 集計したい最後の参照値。数値の場合
  Else
   XX9 = Cells(gyo09, retu09) 集計したい最後の参照値。座標の場合
  End If

 5.積和をとる範囲(最初と最後の行数)を求めます(gyo_cnt91、gyo_cnt99)
  For i = 1 To gyo_cnt1
   If XX = Cells(gyo11 + i - 1, retu11) Then Exit For
  Next
  gyo_cnt91 = i '先頭からの相対的な行数
  For i = 1 To gyo_cnt1
   If XX9 = Cells(gyo11 + i - 1, retu11) Then Exit For
  Next
  gyo_cnt99 = i '先頭からの行数

 6.関数式を作ります
 本体のSumProduct関数を使用します。
 If flag1 = 1 Then '1項目しか指定していない場合
  条件付SUMPRO_02 = Application.WorksheetFunction.Sum(Range(Cells(gyo21 + gyo_cnt91 - 1, retu21), Cells(gyo21 + gyo_cnt99 - 1, retu21)))
 Else
  条件付SUMPRO_02 = Application.WorksheetFunction.SumProduct(Range(Cells(gyo21 + gyo_cnt91 - 1, retu21), Cells(gyo21 + gyo_cnt99 - 1, retu21)), Range(Cells(gyo31 + gyo_cnt91 - 1, retu31), Cells(gyo31 + gyo_cnt99 - 1, retu31)))
 End If

 こんなものでしょうか。

 ここでこんな問題が出てきました。
 仕事ではたまにシミュレーション系のものがあります。その場合は、諸々の機能が複数年必要であり、通常は計算式のコピーで対応可能です。
 しかし、この関数はパラメータとセットになっています。これが単純にコピーできないのです。パラメータ(D20,A42,A20,42,B20,C21)は文字ですからコピーしても座標は変わりません。ここでいうA列は変わらなくてもいいのですが、他のものは変わってほしいです。
 何とかならないのでしょうか。

0 件のコメント: