web-dev-qa-db-ja.com

別のセルの値が変化したときの数式の自動更新(数式で計算)

C2に数式があります。たとえば、=A2+B2です。 C2が値(式ではなく実際の値)を変更するたびに、D2で現在の日付と時刻を更新します。

私はたくさんのVBAコードとトリックを試しましたが、C2に数式が入力された場合、どれも機能しません。しかし、C2に手動で値を入力すると、日時は必要に応じて更新されます。もちろん、これは実際の値が入力/変更されるためです。つまり、公式は同じままです。

質問: C2の数式の結果が変化したときにD2を更新するVBAコード(または何か他のもの)を作成することは可能ですか?

可能であれば、これをセルC2:C30でアクティブにする必要があります(日付+時間の場合は+ D2:D30)

Excel 2010を使用します。

5
AlienHand

C2セルの値を入力パラメーターとして受け取り、現在の日付を出力として返すユーザー定義関数(VBAマクロ関数)によって、依存セル(D2)を埋めることができます。

D2のUDFの入力パラメーターとしてC2を使用すると、C2が変更されるたびに(つまり、ブックで数式の自動計算がオンになっている場合)、D2を再評価する必要があることがExcelに通知されます。

編集:

ここにいくつかのコードがあります:

UDFの場合:

    Public Function UDF_Date(ByVal data) As Date

        UDF_Date = Now()

    End Function

D2の式として:

=UDF_Date(C2)

D2セルに日時形式を指定する必要があります。そうしないと、日付値の数値表現が表示されます。

また、C2の参照をD2の式と相対的に保つ場合は、式をドラッグすることで目的の範囲に拡張できます。

注: Excelがブックを再計算するたびにD2の日付が現在の値にリセットされるため、これはまだ理想的な解決策ではない可能性があります。 D2にC2が最後に変更されたときのみを反映させるには、C2の過去の値を追跡する必要があります。これは、たとえば、入力パラメーターの値の横のアドレスも提供し、非表示のシートに入力パラメーターを格納し、UDFが呼び出されるたびに以前の値と比較することにより、UDFに実装できます。

補遺:

次に、セル値の変更を追跡し、最後の変更が検出された日時を返すUDFの実装例を示します。使用する場合は、次のことに注意してください。

  • UDFの使用方法は、上記と同じです。

  • UDFは、単一セルの入力範囲に対してのみ機能します。

  • セルの値は、セルの最後の値と、ブックのドキュメントプロパティで変更が検出された日時を格納することによって追跡されます。数式が大きなデータセットで使用される場合、ファイルのサイズは大幅に増加する可能性があります。数式によって追跡されるすべてのセルについて、ストレージ要件が増加します(セルの最後の値+最終変更日)。また、Excelは、非常に大量のドキュメントプロパティとコードを処理すると、特定の時点でブレーキがかかる場合があります。

  • ワークシートの名前が変更されると、そこに含まれるセルのすべての追跡情報が失われます。

  • コードは、文字列への変換が非決定的であるセル値を停止する可能性があります。

  • 以下のコードはテストされていませんであり、概念実証としてのみ見なされます。 自己責任で使用してください

    Public Function UDF_Date(ByVal inData As Range) As Date
    
        Dim wb As Workbook
        Dim dProps As DocumentProperties
        Dim pValue As DocumentProperty
        Dim pDate As DocumentProperty
        Dim sName As String
        Dim sNameDate As String
    
        Dim bDate As Boolean
        Dim bValue As Boolean
        Dim bChanged As Boolean
    
        bDate = True
        bValue = True
    
        bChanged = False
    
    
        Dim sVal As String
        Dim dDate As Date
    
        sName = inData.Address & "_" & inData.Worksheet.Name
        sNameDate = sName & "_dat"
    
        sVal = CStr(inData.Value)
        dDate = Now()
    
        Set wb = inData.Worksheet.Parent
    
        Set dProps = wb.CustomDocumentProperties
    
    On Error Resume Next
    
        Set pValue = dProps.Item(sName)
    
        If Err.Number <> 0 Then
            bValue = False
            Err.Clear
        End If
    
    On Error GoTo 0
    
        If Not bValue Then
            bChanged = True
            Set pValue = dProps.Add(sName, False, msoPropertyTypeString, sVal)
        Else
            bChanged = pValue.Value <> sVal
            If bChanged Then
                pValue.Value = sVal
            End If
        End If
    
    On Error Resume Next
    
        Set pDate = dProps.Item(sNameDate)
    
        If Err.Number <> 0 Then
            bDate = False
            Err.Clear
        End If
    
    On Error GoTo 0
    
        If Not bDate Then
            Set pDate = dProps.Add(sNameDate, False, msoPropertyTypeDate, dDate)
        End If
    
        If bChanged Then
            pDate.Value = dDate
        Else
            dDate = pDate.Value
        End If
    
    
        UDF_Date = dDate
     End Function
    
10
Roman

範囲を条件として日付の挿入を行います。

これには、セルの内容が変更されない限り日付が変更されないという利点があります。また、C2:C2の範囲内であれば、シートを閉じて保存しても、隣接するセルが変更されない限り再計算されません。

このヒント と@Paul Sからの回答

Private Sub Worksheet_Change(ByVal Target As Range)
 Dim R1 As Range
 Dim R2 As Range
 Dim InRange As Boolean
    Set R1 = Range(Target.Address)
    Set R2 = Range("C2:C20")
    Set InterSectRange = Application.Intersect(R1, R2)

  InRange = Not InterSectRange Is Nothing
     Set InterSectRange = Nothing
   If InRange = True Then
     R1.Offset(0, 1).Value = Now()
   End If
     Set R1 = Nothing
     Set R2 = Nothing
 End Sub
4
datatoo

最も簡単な方法は、=IF(B3="","Not Allocated",Now())を追加して、列の形式を必要な日付と時刻の形式に変更することです。ただし、ここでB列を編集すると、古い値をチェックしないため、更新が必要な各列の日付と時刻がすべての列に対して自動的に更新されます。しかし、現在の時刻を取得するのに問題がなければ、これは簡単に使用できます。

0
Arun Chettoor
Private Sub Worksheet_Change(ByVal Target As Range)

    If Target.Address = "$C$2" Then

        ActiveSheet.Range("D2").Value = Now()

    End If

End Sub
0
Paul S