fix: テーブル書込みをDataBodyRangeプロパティに依存しない実装に全面変更
DataBodyRangeは、直前と同一サイズへのResizeだけでなくヘッダ+1データ行という特定サイズへのResizeでも 内部状態が更新されずNothingのままになるケースがあり、tempRows経由の2段階Resizeでも解消しなかった。 根本対応として、exportCSVDataToSheet/getRecordsDataToSheet/exportCSVDataToExistingTableの3関数で DataBodyRangeを一切使わず、tbl.Range(ヘッダ含む全体範囲)から直接Offset/Resizeで計算したRangeに クリア・書き込みを行う方式に統一。調査用デバッグログも整理した。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
97f371db3f
commit
0544365276
@ -190,8 +190,8 @@ Function exportCSVDataToSheet(csvData As Variant, targetSheet As String)
|
|||||||
Set tblEmpty = ws.ListObjects(targetSheet)
|
Set tblEmpty = ws.ListObjects(targetSheet)
|
||||||
On Error GoTo 0
|
On Error GoTo 0
|
||||||
If Not tblEmpty Is Nothing Then
|
If Not tblEmpty Is Nothing Then
|
||||||
If Not tblEmpty.DataBodyRange Is Nothing Then
|
If tblEmpty.Range.Rows.count > 1 Then
|
||||||
tblEmpty.DataBodyRange.ClearContents
|
tblEmpty.Range.Resize(tblEmpty.Range.Rows.count - 1, tblEmpty.Range.Columns.count).Offset(1, 0).ClearContents
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Exit Function
|
Exit Function
|
||||||
@ -236,17 +236,13 @@ Function exportCSVDataToSheet(csvData As Variant, targetSheet As String)
|
|||||||
tbl.Name = targetSheet
|
tbl.Name = targetSheet
|
||||||
End If
|
End If
|
||||||
|
|
||||||
'テーブルのデータ部分をクリア
|
'既存データ部分を毎回クリア(DataBodyRangeプロパティは内部状態が更新されず
|
||||||
If Not tbl.DataBodyRange Is Nothing Then
|
'Nothingのままになることがあるため使わず、テーブル範囲から直接計算する)
|
||||||
tbl.DataBodyRange.ClearContents
|
If tbl.Range.Rows.count > 1 Then
|
||||||
|
tbl.Range.Resize(tbl.Range.Rows.count - 1, tbl.Range.Columns.count).Offset(1, 0).ClearContents
|
||||||
End If
|
End If
|
||||||
|
|
||||||
' テーブルにデータを追加(ヘッダ行(arr(0,*))を除いたデータ部分のみをDataBodyRangeに書き込む)
|
' テーブルを目的のサイズにリサイズ
|
||||||
'直前と同一サイズへのResizeだとExcelがDataBodyRangeの内部状態を更新しないことがあるため、
|
|
||||||
'一旦ヘッダ行のみにリサイズしてから目的のサイズにリサイズし直す
|
|
||||||
Dim tempRows As Long
|
|
||||||
tempRows = tbl.Range.Rows.count + rows.count + 1
|
|
||||||
tbl.Resize tbl.Range.Resize(tempRows, maxCols)
|
|
||||||
tbl.Resize tbl.Range.Resize(rows.count, maxCols)
|
tbl.Resize tbl.Range.Resize(rows.count, maxCols)
|
||||||
|
|
||||||
Dim dataArr() As Variant
|
Dim dataArr() As Variant
|
||||||
@ -256,7 +252,11 @@ Function exportCSVDataToSheet(csvData As Variant, targetSheet As String)
|
|||||||
dataArr(i, j) = arr(i, j - 1)
|
dataArr(i, j) = arr(i, j - 1)
|
||||||
Next j
|
Next j
|
||||||
Next i
|
Next i
|
||||||
tbl.DataBodyRange.Value = dataArr
|
|
||||||
|
'データ書き込み(DataBodyRangeプロパティを使わず、ヘッダ行の次からテーブル範囲を直接計算する)
|
||||||
|
Dim dataRange As Range
|
||||||
|
Set dataRange = tbl.Range.Resize(rows.count - 1, maxCols).Offset(1, 0)
|
||||||
|
dataRange.Value = dataArr
|
||||||
|
|
||||||
'------------------------------------------
|
'------------------------------------------
|
||||||
Debug.Print "CSVデータをシートに出力完了: " & targetSheet
|
Debug.Print "CSVデータをシートに出力完了: " & targetSheet
|
||||||
@ -484,23 +484,19 @@ Function getRecordsDataToSheet(records As Collection, targetSheet As String)
|
|||||||
Set tblEmpty = ws.ListObjects(targetSheet)
|
Set tblEmpty = ws.ListObjects(targetSheet)
|
||||||
On Error GoTo 0
|
On Error GoTo 0
|
||||||
If Not tblEmpty Is Nothing Then
|
If Not tblEmpty Is Nothing Then
|
||||||
If Not tblEmpty.DataBodyRange Is Nothing Then
|
If tblEmpty.Range.Rows.count > 1 Then
|
||||||
tblEmpty.DataBodyRange.ClearContents
|
tblEmpty.Range.Resize(tblEmpty.Range.Rows.count - 1, tblEmpty.Range.Columns.count).Offset(1, 0).ClearContents
|
||||||
End If
|
End If
|
||||||
End If
|
End If
|
||||||
Exit Function
|
Exit Function
|
||||||
End If
|
End If
|
||||||
|
|
||||||
Debug.Print " [DEBUG] records.count = " & records.count
|
|
||||||
|
|
||||||
Dim flatRecords As New Collection
|
Dim flatRecords As New Collection
|
||||||
Dim rec As Dictionary
|
Dim rec As Dictionary
|
||||||
For Each rec In records
|
For Each rec In records
|
||||||
flatRecords.Add FlattenRecord(rec)
|
flatRecords.Add FlattenRecord(rec)
|
||||||
Next rec
|
Next rec
|
||||||
|
|
||||||
Debug.Print " [DEBUG] flatRecords.count = " & flatRecords.count
|
|
||||||
|
|
||||||
Dim headerDict As Dictionary
|
Dim headerDict As Dictionary
|
||||||
Set headerDict = flatRecords(1)
|
Set headerDict = flatRecords(1)
|
||||||
Dim headerKeys As Variant
|
Dim headerKeys As Variant
|
||||||
@ -508,8 +504,6 @@ Function getRecordsDataToSheet(records As Collection, targetSheet As String)
|
|||||||
Dim maxCols As Long
|
Dim maxCols As Long
|
||||||
maxCols = headerDict.count
|
maxCols = headerDict.count
|
||||||
|
|
||||||
Debug.Print " [DEBUG] maxCols = " & maxCols
|
|
||||||
|
|
||||||
Dim i As Long, j As Long
|
Dim i As Long, j As Long
|
||||||
Dim dataArr() As Variant
|
Dim dataArr() As Variant
|
||||||
ReDim dataArr(1 To flatRecords.count, 1 To maxCols)
|
ReDim dataArr(1 To flatRecords.count, 1 To maxCols)
|
||||||
@ -521,16 +515,11 @@ Function getRecordsDataToSheet(records As Collection, targetSheet As String)
|
|||||||
Next j
|
Next j
|
||||||
Next i
|
Next i
|
||||||
|
|
||||||
Debug.Print " [DEBUG] dataArr dims = " & UBound(dataArr, 1) & " x " & UBound(dataArr, 2)
|
|
||||||
Debug.Print " [DEBUG] dataArr(1,1) = " & CStr(dataArr(1, 1)) & " / dataArr(1,2) = " & CStr(dataArr(1, 2))
|
|
||||||
|
|
||||||
Dim tbl As ListObject
|
Dim tbl As ListObject
|
||||||
On Error Resume Next
|
On Error Resume Next
|
||||||
Set tbl = ws.ListObjects(targetSheet)
|
Set tbl = ws.ListObjects(targetSheet)
|
||||||
On Error GoTo 0
|
On Error GoTo 0
|
||||||
|
|
||||||
Debug.Print " [DEBUG] tbl Is Nothing (before) = " & (tbl Is Nothing)
|
|
||||||
|
|
||||||
Dim headerRange As Range
|
Dim headerRange As Range
|
||||||
Set headerRange = ws.Range("A1").Resize(1, maxCols)
|
Set headerRange = ws.Range("A1").Resize(1, maxCols)
|
||||||
For j = 0 To maxCols - 1
|
For j = 0 To maxCols - 1
|
||||||
@ -543,25 +532,19 @@ Function getRecordsDataToSheet(records As Collection, targetSheet As String)
|
|||||||
tbl.Name = targetSheet
|
tbl.Name = targetSheet
|
||||||
End If
|
End If
|
||||||
|
|
||||||
Debug.Print " [DEBUG] tbl.Range.Address (before resize) = " & tbl.Range.Address
|
'既存データ部分を毎回クリア(DataBodyRangeプロパティは内部状態が更新されず
|
||||||
|
'Nothingのままになることがあるため使わず、テーブル範囲から直接計算する)
|
||||||
If Not tbl.DataBodyRange Is Nothing Then
|
If tbl.Range.Rows.count > 1 Then
|
||||||
tbl.DataBodyRange.ClearContents
|
tbl.Range.Resize(tbl.Range.Rows.count - 1, tbl.Range.Columns.count).Offset(1, 0).ClearContents
|
||||||
End If
|
End If
|
||||||
|
|
||||||
'テーブル範囲が直前と同一サイズだとExcelがDataBodyRangeの内部状態を更新しないことがあるため、
|
' テーブルを目的のサイズにリサイズ
|
||||||
'一旦ヘッダ行のみにリサイズしてから目的のサイズにリサイズし直す
|
|
||||||
Dim tempRows As Long
|
|
||||||
tempRows = tbl.Range.Rows.count + flatRecords.count + 2
|
|
||||||
tbl.Resize tbl.Range.Resize(tempRows, maxCols)
|
|
||||||
tbl.Resize tbl.Range.Resize(flatRecords.count + 1, maxCols)
|
tbl.Resize tbl.Range.Resize(flatRecords.count + 1, maxCols)
|
||||||
Debug.Print " [DEBUG] tbl.Range.Address (after resize) = " & tbl.Range.Address
|
|
||||||
Debug.Print " [DEBUG] tbl.DataBodyRange Is Nothing (after resize) = " & (tbl.DataBodyRange Is Nothing)
|
'データ書き込み(DataBodyRangeプロパティを使わず、ヘッダ行の次からテーブル範囲を直接計算する)
|
||||||
If Not tbl.DataBodyRange Is Nothing Then
|
Dim dataRange As Range
|
||||||
Debug.Print " [DEBUG] tbl.DataBodyRange.Address = " & tbl.DataBodyRange.Address & " / Rows.count=" & tbl.DataBodyRange.Rows.count & " / Columns.count=" & tbl.DataBodyRange.Columns.count
|
Set dataRange = tbl.Range.Resize(flatRecords.count, maxCols).Offset(1, 0)
|
||||||
End If
|
dataRange.Value = dataArr
|
||||||
tbl.DataBodyRange.Value = dataArr
|
|
||||||
Debug.Print " [DEBUG] after assign, A2 cell value = [" & ws.Range("A2").Value & "]"
|
|
||||||
|
|
||||||
Debug.Print "レコードのシート出力完了: " & targetSheet
|
Debug.Print "レコードのシート出力完了: " & targetSheet
|
||||||
End Function
|
End Function
|
||||||
@ -690,7 +673,10 @@ Function exportCSVDataToExistingTable(csvData As Variant, tableName As String)
|
|||||||
Set rows = ParseCsv(csvData)
|
Set rows = ParseCsv(csvData)
|
||||||
|
|
||||||
If rows.count <= 1 Then
|
If rows.count <= 1 Then
|
||||||
MsgBox "データが存在しません(ヘッダのみ): " & tableName, vbExclamation
|
Debug.Print "データが0件のため、既存テーブルのデータ部分をクリアします: " & tableName
|
||||||
|
If tbl.Range.Rows.count > 1 Then
|
||||||
|
tbl.Range.Resize(tbl.Range.Rows.count - 1, tbl.Range.Columns.count).Offset(1, 0).ClearContents
|
||||||
|
End If
|
||||||
Exit Function
|
Exit Function
|
||||||
End If
|
End If
|
||||||
|
|
||||||
@ -712,15 +698,13 @@ Function exportCSVDataToExistingTable(csvData As Variant, tableName As String)
|
|||||||
i = i + 1
|
i = i + 1
|
||||||
Next rowArr
|
Next rowArr
|
||||||
|
|
||||||
If Not tbl.DataBodyRange Is Nothing Then
|
'既存データ部分を毎回クリア(DataBodyRangeプロパティは内部状態が更新されず
|
||||||
tbl.DataBodyRange.ClearContents
|
'Nothingのままになることがあるため使わず、テーブル範囲から直接計算する)
|
||||||
|
If tbl.Range.Rows.count > 1 Then
|
||||||
|
tbl.Range.Resize(tbl.Range.Rows.count - 1, tbl.Range.Columns.count).Offset(1, 0).ClearContents
|
||||||
End If
|
End If
|
||||||
|
|
||||||
'直前と同一サイズへのResizeだとExcelがDataBodyRangeの内部状態を更新しないことがあるため、
|
' テーブルを目的のサイズにリサイズ
|
||||||
'一旦ヘッダ行のみにリサイズしてから目的のサイズにリサイズし直す
|
|
||||||
Dim tempRows As Long
|
|
||||||
tempRows = tbl.Range.Rows.count + rows.count + 1
|
|
||||||
tbl.Resize tbl.Range.Resize(tempRows, maxCols)
|
|
||||||
tbl.Resize tbl.Range.Resize(rows.count, maxCols)
|
tbl.Resize tbl.Range.Resize(rows.count, maxCols)
|
||||||
|
|
||||||
Dim dataArr() As Variant
|
Dim dataArr() As Variant
|
||||||
@ -730,7 +714,11 @@ Function exportCSVDataToExistingTable(csvData As Variant, tableName As String)
|
|||||||
dataArr(i, j) = arr(i, j - 1)
|
dataArr(i, j) = arr(i, j - 1)
|
||||||
Next j
|
Next j
|
||||||
Next i
|
Next i
|
||||||
tbl.DataBodyRange.Value = dataArr
|
|
||||||
|
'データ書き込み(DataBodyRangeプロパティを使わず、ヘッダ行の次からテーブル範囲を直接計算する)
|
||||||
|
Dim dataRange As Range
|
||||||
|
Set dataRange = tbl.Range.Resize(rows.count - 1, maxCols).Offset(1, 0)
|
||||||
|
dataRange.Value = dataArr
|
||||||
|
|
||||||
Debug.Print "CSVデータを既存テーブルに出力完了: " & tableName
|
Debug.Print "CSVデータを既存テーブルに出力完了: " & tableName
|
||||||
End Function
|
End Function
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user