Excel (VBA) |
![]() ![]() |
(Windows 10 Pro : Excel 2016)
変換データを利用した行の挿入について
投稿日時: 23/06/06 10:57:01
投稿者: ひろまさ
|
---|---|
アドバイスを頂きたい事がございます。
|
![]() |
投稿日時: 23/06/06 11:50:34
投稿者: simple
|
---|---|
挿入処理を行う際は、k の繰り返しを下から上に順次実行してください。
|
![]() |
投稿日時: 23/06/06 12:04:46
投稿者: ひろまさ
|
---|---|
simple様
|
![]() |
投稿日時: 23/06/06 12:11:11
投稿者: simple
|
---|---|
For k = Sh2.Cells(Rows.Count, 1).End(xlUp).Row To 2 Step -1
|
![]() |
投稿日時: 23/06/06 13:28:58
投稿者: Suzu
|
---|---|
「商品」を元に考えるのではなく、「変換」を元に考えてはいかがでしょうか?
商品CD1 商品CD2 割合 時間 A あ 30 B い 0.5 20 B い 0.5 20 こうするのは、一般関数だけで行けます。 時間 の下 に =INDEX(商品!A$2:B$3,MATCH(A3,商品!A$2:A$3,0),2) として、下方向オートフィル で出ます。 並び順を、シート 商品の並びと同じにしたいなら 商品を 商品CD1 時間 並び B 20 1 A 30 2 の様に、並び の 列を追加 商品CD1 商品CD2 割合 時間 並び A あ 30 2 B い 0.5 20 1 B い 0.5 20 1 並び の 式は =INDEX(商品!A$2:C$3,MATCH($A3,商品!A$2:A$3,0),3) で、出せますから、 あとは、 割合と時間との積を求め、 並び で並べ替え を行い 範囲をコピーし、値貼り付け を行い、数式から、数値に変換 不要な列を削除 で求める表を得られますね。 |
![]() |
投稿日時: 23/06/06 13:42:53
投稿者: ひろまさ
|
---|---|
simple様
|
![]() |
投稿日時: 23/06/06 14:03:17
投稿者: Suzu
|
---|---|
PowerQueryを使用しても良いでしょう。
|
![]() |
投稿日時: 23/06/06 14:24:22
投稿者: ひろまさ
|
---|---|
Suzu様
|
![]() |
投稿日時: 23/06/06 16:27:42
投稿者: ひろまさ
|
---|---|
誠に恐縮ではございますが、やはり、Suzu様がおっしゃる通りに「商品」を元に考える
|
![]() |
投稿日時: 23/06/06 17:14:51
投稿者: sk
|
---|---|
引用: 逆にお聞きしたいのですが、[商品シート]そのものを書き換えようと されているのは、どういった目的や動機からなのでしょうか。 例えば、「変換後の結果」を別のワークシートに出力するなどした方が 安全だと思いますが。 引用: 引用: なさろうとしている処理を一言でまとめれば「数値の按分」だと思われますが、 小数値を掛けた結果として生じた端数はどのように扱われるつもりなのでしょうか。 下手なやり方をすれば、「元の数値」と「按分された値の合計」が一致しない という結果をもたらしかねず、変換前の状態に復元しようにも、按分によって生じた 端数のずれによって正しく復元することができなくなる(不可逆的なデータ変換処理となる) 恐れがあります。 |
![]() |
投稿日時: 23/06/06 17:37:01
投稿者: ひろまさ
|
---|---|
sk様お返事ありがとうございます。
|
![]() |
投稿日時: 23/06/06 17:43:09
投稿者: 半平太
|
---|---|
商品シートに有って、変換シートに無かったら、どうするんですか?
|
![]() |
投稿日時: 23/06/06 17:51:22
投稿者: sk
|
---|---|
引用: その構成の定義づけを表しているのが[変換シート]上のデータなのであれば、 この処理の主体となるのも[変換シート]の方でしょう。 [商品シート]上のデータは、[商品CD1]グループごとに按分元となる数値を 参照するためだけのものとして捉えられた方が分かりやすいでしょう。 |
![]() |
投稿日時: 23/06/06 20:12:46
投稿者: ひろまさ
|
---|---|
半平太様
|
![]() |
投稿日時: 23/06/06 21:05:12
投稿者: simple
|
---|---|
行の挿入は負荷がある処理なので、1万行もあると効率悪いと思いますが、
If Sh1.Cells(i, 3) <> "" Then l = Sh1.Cells(i, 3) Sh2.Cells(k, 2) = l * Sh2.Cells(k, 2) 'k+1行目に一行挿入 'そのA列にコードを書きこむ 'B列に、時間×割合を書き込む End If # 挿入ではなく、既に指摘いただいているように、現在の商品シートはそのまま残し、 # 第三のシートに、商品シートと変換シートを用いて、 # 上から順次転記していくほうが効率は良い気がします。 # 結果をいったん配列に保持して、一括して書き込むともっと効率はよいでしょう。 |
![]() |
投稿日時: 23/06/06 22:40:18
投稿者: 半平太
|
---|---|
行挿入はストレスが掛かると思うので、
Sub henkan() Dim Sh1 As Worksheet Dim Sh2 As Worksheet Dim i As Long Dim k As Long Dim tempKey As Long Dim dicT As Object Dim dicOut As Object Dim vSRC Dim spl, subSpl, bufTime Set Sh1 = Sheets("変換") Set Sh2 = Sheets("商品") Set dicT = CreateObject("Scripting.Dictionary") Set dicOut = CreateObject("Scripting.Dictionary") '変換用を作成 For i = 2 To Sh1.Cells(Rows.Count, 1).End(xlUp).Row dicT(Sh1.Cells(i, "A").Value) = dicT(Sh1.Cells(i, "A").Value) & "#!#" & _ Sh1.Cells(i, "B") & "♪" & Sh1.Cells(i, "C") Next i '商品データ格納 vSRC = Sh2.Range("A1", Sh2.Cells(Rows.Count, 1).End(xlUp)).Resize(, 2).Value '変換実行 tempKey = 2 For i = 2 To UBound(vSRC) If dicT(vSRC(i, 1)) = Empty Then dicOut(tempKey) = Array(vSRC(i, 1), vSRC(i, 2)) 'そのまま出力 tempKey = tempKey + 1 Else bufTime = vSRC(i, 2) spl = Split(dicT(vSRC(i, 1)), "#!#") '同種コードを分解 For k = 1 To UBound(spl) subSpl = Split(spl(k), "♪") dicOut(tempKey) = Array(subSpl(0), IIf(IsNumeric(subSpl(1)), _ bufTime * Val(subSpl(1)), bufTime)) tempKey = tempKey + 1 Next k End If Next i '出力 Sh2.Range("A2:B2").Resize(dicOut.Count) = Application.Index(dicOut.items, 0) End Sub |
![]() |
投稿日時: 23/06/06 23:49:03
投稿者: ひろまさ
|
---|---|
simple様
|
![]() |
投稿日時: 23/06/07 06:56:25
投稿者: simple
|
---|---|
(1)Rows(k+1)のワークシート指定がありません。
|
![]() |
投稿日時: 23/06/07 09:50:55
投稿者: ひろまさ
|
---|---|
半平太様
|
![]() |
投稿日時: 23/06/07 11:40:09
投稿者: Suzu
|
---|---|
引用: なら 商品CD1 時間 い 5 い 3 い 2 い 2.5 い 1.5 い 1 あ 30 なのではなくて? If Sh1.Cells(i, 3) <> "" Then l = Sh1.Cells(i, 3) Sh2.Cells(k, 2) = l * Sh2.Cells(k, 2) Rows(k + 1).Insert Sh2.Cells(k + 1, 1) = Sh1.Cells(i, 2) Sh2.Cells(k + 1, 2) = l * Sh2.Cells(k, 2) End If 按分が、2件なら、上記でも良いでしょうが 3件以上の場合を考慮すると、上記の赤の部分をループ処理を行う必要があります。 その点、 引用: 変換を元にすれば、按分分の行は既に用意されていますから、挿入の必要がありません。 商品には、データがあるが、変換には無い場合、追加の必要がありますが。 その辺は、 『元のデータに上記の様に 商品にはあるが、変換には無い』 が あり得るかで判断すれば良いでしょう。 |
![]() |
投稿日時: 23/06/07 13:45:59
投稿者: sk
|
---|---|
引用: (標準モジュール) ----------------------------------------------------------------- Sub CreateApportionmentSheet() Dim wbkSource As Excel.Workbook Set wbkSource = ThisWorkbook Dim wsProduct As Excel.Worksheet Dim lngFirstProductRow As Long Dim lngLastProductRow As Long Set wsProduct = wbkSource.Worksheets("商品") With wsProduct lngFirstProductRow = 2 lngLastProductRow = .Cells(.Rows.Count, 1).End(xlUp).Row If lngLastProductRow < lngFirstProductRow Then Set wsProduct = Nothing Set wbkSource = Nothing End If End With Dim wsDetail As Excel.Worksheet Set wsDetail = wbkSource.Worksheets("変換") Dim wsResult As Excel.Worksheet On Error Resume Next Set wsResult = wbkSource.Worksheets("変換結果") If Err.Number <> 0 Then Err.Clear On Error GoTo 0 Set wsResult = wbkSource.Worksheets.Add(After:=wsDetail) wsResult.Name = "変換結果" End If On Error GoTo 0 Dim lngResultRow As Long With wsResult lngResultRow = 1 .Cells.Clear .Cells(lngResultRow, 1).Value = "商品CD1" .Cells(lngResultRow, 2).Value = "時間" End With Dim rngSearchArea As Excel.Range Dim rngFound As Excel.Range Dim varProductId As Variant Dim varTotalTime As Variant Dim varModelId As Variant Dim varApportionmentRatio As Variant Dim strFirstAddress As String Dim lngProductRow As Long Application.ReplaceFormat.Clear Set rngSearchArea = wsDetail.Columns(1) For lngProductRow = lngFirstProductRow To lngLastProductRow strFirstAddress = "" varProductId = wsProduct.Cells(lngProductRow, 1).Value varTotalTime = wsProduct.Cells(lngProductRow, 2).Value If varProductId <> "" Then Set rngFound = rngSearchArea.Find(What:=varProductId, LookIn:=xlValues, _ LookAt:=xlWhole, SearchDirection:=xlNext, _ MatchCase:=True, MatchByte:=True) If Not rngFound Is Nothing Then strFirstAddress = rngFound.Address Do varModelId = rngFound.Offset(0, 1).Value varApportionmentRatio = rngFound.Offset(0, 2).Value lngResultRow = lngResultRow + 1 wsResult.Cells(lngResultRow, 1).Value = varModelId If IsEmpty(varApportionmentRatio) = False And IsNumeric(varApportionmentRatio) = True Then wsResult.Cells(lngResultRow, 2).Value = varTotalTime * CDbl(varApportionmentRatio) Else wsResult.Cells(lngResultRow, 2).Value = varTotalTime End If Set rngFound = rngSearchArea.FindNext(rngFound) Loop While Not rngFound Is Nothing And rngFound.Address <> strFirstAddress Else lngResultRow = lngResultRow + 1 wsResult.Cells(lngResultRow, 1).Value = varProductId wsResult.Cells(lngResultRow, 2).Value = varTotalTime End If End If Next With wsResult .UsedRange.EntireColumn.AutoFit .Select .Cells(1, 1).Select End With Set rngSearchArea = Nothing Set wsResult = Nothing Set wsDetail = Nothing Set wsProduct = Nothing Set wbkSource = Nothing End Sub ----------------------------------------------------------------- 上記のマクロを実行したのと同様の結果を得られればよい、ということでしょうか。 |
![]() |
投稿日時: 23/06/08 08:32:14
投稿者: ひろまさ
|
---|---|
Suzu様
|
![]() |
投稿日時: 23/06/08 08:33:25
投稿者: ひろまさ
|
---|---|
解決済みにさせて頂きます。 |