CREATING TABLE ARCHIVE TO STORE ALL DELETED RECORDS

Kamayo Ako

Member
Local time
Today, 21:05
Joined
May 23, 2022
Messages
92
Is it possible to dedicate one table (tblArchive) and all deleted records from any transaction will save there. Thank you for any possible way on how to achieve. I try append and delete query but i need to make to all transaction tables since fields are not identical.
 
It's possible, just takes a bunch of code. Simpler would be to set a field value and apply filter to exclude from query.

What do you mean by "all transaction tables" - why are there multiple transaction tables? If they are different, then you need multiple archive tables?
 
It's possible, just takes a bunch of code. Simpler would be to set a field value and apply filter to exclude from query.

What do you mean by "all transaction tables" - why are there multiple transaction tables? If they are different, then you need multiple archive tables?
what i mean sir is that. I have one table name: tblArchive. now i have other tables like - Purchase Order/Details - Inbound (ReceivedItems) and outbound(Issued Items) and so on. So If I delete records in any those tables for some reasons then that should be store in tblArchive.
 
For an exact archive, the structure of the archive table must match the structure of the table being archived, field for field, with possible exceptions based on how you will detect the records to be archived. What I usually did was I had a flag (Yes/No) that said "Ready to be archived." I would set it based on other tests. I always had down-time available for the DB, not less than once per four weeks but sometimes once per week. When the DB went out of service, I ran two queries. The first was an INSERT INTO that took the marked records from the table to be archived and put them into the archiving table. The second query was a DELETE of marked records. In cases where there were child records, I also had something to move those child records FIRST (because of non-orphan rules).

It is possible that the records would match exactly if archiving was a matter of a fixed age of the given records. If I used an "archive" Y/N marker, that didn't have to be copied to the archiving table because if a record was there, its marker was "YES" at some point.

EDIT: In response to your late-arriving post, Access would work best if you have one separate archive table for each table to be archived.
 
create Separate Archive table for each table you want to archive.
you create a Function/Sub that will handle the Insertion of record to Archive table
and the Deletion of record from your table.

Archive table will not will not save the Autonumber as Autonumber, but saved as Ordinary Long number of transaction table.
what the table will hold, in addition to the Same structure of the trans table (except the autonumber),
is a Timestamp field when the archive took place.
therefore you can selectively "recall" the records by identifying the Timestamp.
 
Last edited:
Lots of confusing words have been typed since, but June gave you the correct answer in her 2nd sentence:

Simpler would be to set a field value and apply filter to exclude from query.

Add a yes/no field to every table you want to 'delete' from called [Deleted] and set it to true when necessary. That's it, nothing more to do, mission accomplished, no action queries, no convoluted code to move data to any deleted-but-not-really table. Just those [Deleted] fields is all you need.
 
For an exact archive, the structure of the archive table must match the structure of the table being archived, field for field, with possible exceptions based on how you will detect the records to be archived. What I usually did was I had a flag (Yes/No) that said "Ready to be archived." I would set it based on other tests. I always had down-time available for the DB, not less than once per four weeks but sometimes once per week. When the DB went out of service, I ran two queries. The first was an INSERT INTO that took the marked records from the table to be archived and put them into the archiving table. The second query was a DELETE of marked records. In cases where there were child records, I also had something to move those child records FIRST (because of non-orphan rules).

It is possible that the records would match exactly if archiving was a matter of a fixed age of the given records. If I used an "archive" Y/N marker, that didn't have to be copied to the archiving table because if a record was there, its marker was "YES" at some point.

EDIT: In response to your late-arriving post, Access would work best if you have one separate archive table for each table to be archived.
Thank you sir.
 
create Separate Archive table for each table you want to archive.
you create a Function/Sub that will handle the Insertion of record to Archive table
and the Deletion of record from your table.

Archive table will not will not save the Autonumber as Autonumber, but saved as Ordinary Long number of transaction table.
what the table will hold, in addition to the Same structure of the trans table (except the autonumber),
is a Timestamp field when the archive took place.
therefore you can selectively "recall" the records by identifying the Timestamp.
That's great idea sir. Timestamp well help also to track the transaction and possible to recall.
 
That's great idea sir. Timestamp well help also to track the transaction and possible to recall.
It's not that simple. You can't reinsert that record without a lot of messing about if the table has an Autonumber Primary key.
That's why the suggestion to use a ArchiveDate or Deleted Flag and leave the record where it is, is the most sensible assuming you aren't running out of space.

Also if you have cascaded deletes set in the relationships, you HAVE to ensure you have copied any child records to suitable archive tables as well.
 
It's not that simple. You can't reinsert that record without a lot of messing about if the table has an Autonumber Primary key.
That's why the suggestion to use a ArchiveDate or Deleted Flag and leave the record where it is, is the most sensible assuming you aren't running out of space.

Also if you have cascaded deletes set in the relationships, you HAVE to ensure you have copied any child records to suitable archive tables as well.
Thank you so much sir.
 
and here is a code that kept me busy during this time.
Code:
' arnelgp
'
' NOTE:
'
' Requirement is that Source table must have
' Autonumber field.
' Both Source and Archive table have same
' field names and type except that the
' equivalent field of Autonumber on source
' table is Normal Long to the Archive table.
'
' also the archive table must have a timestamp (date/time) field.
'
' not much documentation on the code so you need to figure it out.
'
Public Function fnArchive( _
                    ByVal stTable As String, _
                    ByVal stArchive As String, _
                    ByVal stTimeStampField As String, _
                    Optional ByVal stFilter As String = "")
' this will not test if all tables exists
Dim stSQL As String, stFields As String
Dim autoName As String
Dim db As DAO.Database
Dim rs As DAO.Recordset2
Dim rs2 As DAO.Recordset2
Dim chld As DAO.Recordset2
Dim chld2 As DAO.Recordset2
Dim fd As DAO.Field2, fd2 As DAO.Field2
Dim arrMV() As String
Dim arrTyp() As Integer
Dim i As Integer, j As Integer
Dim t As Variant
Dim sFile As String
fnArchive = True
t = Now
Set db = CurrentDb
ReDim arrMV(1 To 255): ReDim arrTyp(1 To 255)
' open structure of table to delete from
stSQL = "select * from [" & stTable & "] where (0=1);"
Set rs = db.OpenRecordset(stSQL, dbOpenSnapshot, dbReadOnly)
' loop through each fields on source table
' and check if there are multi-value or attachment fields.
With rs
    For i = 0 To .Fields.Count - 1
        Set fd = .Fields(i)
        With fd
            If .Attributes And dbAutoIncrField Then
                'this is the autonumber field
                autoName = .Name
                stFields = stFields & "[" & .Name & "],"
            Else
                If .IsComplex Then
                    ' multivalue or attachment field
                    ' save the fieldname to our array
                    j = j + 1
                    arrMV(j) = .Name
                    ' 0 = MVF       '104
                    ' 1 = attachment
                    arrTyp(j) = 0 - (.Type = 101)
                Else
                    stFields = stFields & "[" & .Name & "],"
                End If
            End If
        End With
    Next
    .Close
End With
Set rs = Nothing
Set fd = Nothing
If j <> 0 Then
    ReDim Preserve arrMV(1 To j): ReDim Preserve arrTyp(1 To j)
End If
stFields = Left$(stFields, Len(stFields) - 1)
' append records to archive table
stSQL = "Insert Into [" & stArchive & "] (" & stFields
' add the timestamp field
stSQL = stSQL & ",[" & stTimeStampField & "]) Select " & stFields & ",p1  From [" & stTable & "]"
If Len(stFilter) <> 0 Then
    stSQL = stSQL & " Where " & stFilter
End If
With db.CreateQueryDef("", stSQL)
    .Parameters(0) = t
    .Execute dbFailOnError
End With
If Not Err Then
    ' do we have MVF?
    ' handle Attachment and MVF
    If j <> 0 Then
        stFields = ""
        For i = 1 To UBound(arrMV)
            stFields = stFields & "[" & arrMV(i) & "],"
        Next
        stFields = Left$(stFields, Len(stFields) - 1)
        stSQL = "select " & "[" & autoName & "]," & stFields & " from [" & stTable & "]"
        If Len(stFilter) <> 0 Then
            stSQL = stSQL & " Where " & stFilter
        End If
        Set rs = db.OpenRecordset(stSQL, dbOpenSnapshot)
        stSQL = "select " & "[" & autoName & "]," & stFields & " from [" & stArchive & "] where [" & stTimeStampField & "]=#" & t & "#"
        Set rs2 = db.OpenRecordset(stSQL, dbOpenDynaset)

        With rs
            .MoveFirst
            Do Until .EOF
                j = 0
                rs2.FindFirst "[" & autoName & "] = " & .Fields(autoName).Value
                rs2.Edit
                For i = 1 To .Fields.Count - 1
                    j = j + 1
                    Set chld = .Fields(arrMV(j)).Value
                    Set chld2 = rs2.Fields(arrMV(j)).Value
                    If Not (chld.BOF And chld.EOF) Then
                        chld.MoveFirst
                        Do Until chld.EOF
                            chld2.AddNew
                            If arrTyp(j) = 0 Then
                                chld2.Fields(0) = chld.Fields(0)
                            Else
                                sFile = Environ$("temp") & "\" & chld.Fields("FileName")
                                If Len(Dir$(sFile)) <> 0 Then
                                    Kill sFile
                                End If
                                chld.Fields("FileData").SaveToFile sFile
                                chld2.Fields("FileData").LoadFromFile sFile
                            End If
                            chld2.Update
                            chld.MoveNext
                        Loop
                    End If
                    Set chld2 = Nothing: Set chld = Nothing
                Next i
                rs2.Update
                .MoveNext
            Loop
            .Close
        End With
        rs2.Close
    End If

    ' finally, delete the records from the source
    stSQL = "delete [" & stTable & "].* from [" & stTable & "]"
    If Len(stFilter) <> 0 Then
        stSQL = stSQL & " Where " & stFilter
    End If
    db.Execute stSQL, dbFailOnError
Else
    fnArchive = False
End If
Set rs = Nothing
Set rs2 = Nothing
Set db = Nothing
End Function
 
and here is a code that kept me busy during this time.
Code:
' arnelgp
'
' NOTE:
'
' Requirement is that Source table must have
' Autonumber field.
' Both Source and Archive table have same
' field names and type except that the
' equivalent field of Autonumber on source
' table is Normal Long to the Archive table.
'
' also the archive table must have a timestamp (date/time) field.
'
' not much documentation on the code so you need to figure it out.
'
Public Function fnArchive( _
                    ByVal stTable As String, _
                    ByVal stArchive As String, _
                    ByVal stTimeStampField As String, _
                    Optional ByVal stFilter As String = "")
' this will not test if all tables exists
Dim stSQL As String, stFields As String
Dim autoName As String
Dim db As DAO.Database
Dim rs As DAO.Recordset2
Dim rs2 As DAO.Recordset2
Dim chld As DAO.Recordset2
Dim chld2 As DAO.Recordset2
Dim fd As DAO.Field2, fd2 As DAO.Field2
Dim arrMV() As String
Dim arrTyp() As Integer
Dim i As Integer, j As Integer
Dim t As Variant
Dim sFile As String
fnArchive = True
t = Now
Set db = CurrentDb
ReDim arrMV(1 To 255): ReDim arrTyp(1 To 255)
' open structure of table to delete from
stSQL = "select * from [" & stTable & "] where (0=1);"
Set rs = db.OpenRecordset(stSQL, dbOpenSnapshot, dbReadOnly)
' loop through each fields on source table
' and check if there are multi-value or attachment fields.
With rs
    For i = 0 To .Fields.Count - 1
        Set fd = .Fields(i)
        With fd
            If .Attributes And dbAutoIncrField Then
                'this is the autonumber field
                autoName = .Name
                stFields = stFields & "[" & .Name & "],"
            Else
                If .IsComplex Then
                    ' multivalue or attachment field
                    ' save the fieldname to our array
                    j = j + 1
                    arrMV(j) = .Name
                    ' 0 = MVF       '104
                    ' 1 = attachment
                    arrTyp(j) = 0 - (.Type = 101)
                Else
                    stFields = stFields & "[" & .Name & "],"
                End If
            End If
        End With
    Next
    .Close
End With
Set rs = Nothing
Set fd = Nothing
If j <> 0 Then
    ReDim Preserve arrMV(1 To j): ReDim Preserve arrTyp(1 To j)
End If
stFields = Left$(stFields, Len(stFields) - 1)
' append records to archive table
stSQL = "Insert Into [" & stArchive & "] (" & stFields
' add the timestamp field
stSQL = stSQL & ",[" & stTimeStampField & "]) Select " & stFields & ",p1  From [" & stTable & "]"
If Len(stFilter) <> 0 Then
    stSQL = stSQL & " Where " & stFilter
End If
With db.CreateQueryDef("", stSQL)
    .Parameters(0) = t
    .Execute dbFailOnError
End With
If Not Err Then
    ' do we have MVF?
    ' handle Attachment and MVF
    If j <> 0 Then
        stFields = ""
        For i = 1 To UBound(arrMV)
            stFields = stFields & "[" & arrMV(i) & "],"
        Next
        stFields = Left$(stFields, Len(stFields) - 1)
        stSQL = "select " & "[" & autoName & "]," & stFields & " from [" & stTable & "]"
        If Len(stFilter) <> 0 Then
            stSQL = stSQL & " Where " & stFilter
        End If
        Set rs = db.OpenRecordset(stSQL, dbOpenSnapshot)
        stSQL = "select " & "[" & autoName & "]," & stFields & " from [" & stArchive & "] where [" & stTimeStampField & "]=#" & t & "#"
        Set rs2 = db.OpenRecordset(stSQL, dbOpenDynaset)

        With rs
            .MoveFirst
            Do Until .EOF
                j = 0
                rs2.FindFirst "[" & autoName & "] = " & .Fields(autoName).Value
                rs2.Edit
                For i = 1 To .Fields.Count - 1
                    j = j + 1
                    Set chld = .Fields(arrMV(j)).Value
                    Set chld2 = rs2.Fields(arrMV(j)).Value
                    If Not (chld.BOF And chld.EOF) Then
                        chld.MoveFirst
                        Do Until chld.EOF
                            chld2.AddNew
                            If arrTyp(j) = 0 Then
                                chld2.Fields(0) = chld.Fields(0)
                            Else
                                sFile = Environ$("temp") & "\" & chld.Fields("FileName")
                                If Len(Dir$(sFile)) <> 0 Then
                                    Kill sFile
                                End If
                                chld.Fields("FileData").SaveToFile sFile
                                chld2.Fields("FileData").LoadFromFile sFile
                            End If
                            chld2.Update
                            chld.MoveNext
                        Loop
                    End If
                    Set chld2 = Nothing: Set chld = Nothing
                Next i
                rs2.Update
                .MoveNext
            Loop
            .Close
        End With
        rs2.Close
    End If

    ' finally, delete the records from the source
    stSQL = "delete [" & stTable & "].* from [" & stTable & "]"
    If Len(stFilter) <> 0 Then
        stSQL = stSQL & " Where " & stFilter
    End If
    db.Execute stSQL, dbFailOnError
Else
    fnArchive = False
End If
Set rs = Nothing
Set rs2 = Nothing
Set db = Nothing
End Function
Thank you so much sir
 
Think first, then act.

Deleting and archiving means you want to remove something and still keep it. What now?

What would you like to do with the archive later?

Is it possible that the original tables are too big and confusing for you? Is it possible that because of the large tables, the performance of the queries based on them is unsatisfactory? Is it possible that you want to reduce the original tables because of this?

I would say: It is a basic ability of a database developer to keep track of large amounts of data and to have all processing including queries executed quickly enough so that the user does not experience any problems. You can learn this basic skill and thus avoid a lot of workarounds, which can bring with them a variety of problems and causes of errors.
 
Think first, then act.

Deleting and archiving means you want to remove something and still keep it. What now?

What would you like to do with the archive later?

Is it possible that the original tables are too big and confusing for you? Is it possible that because of the large tables, the performance of the queries based on them is unsatisfactory? Is it possible that you want to reduce the original tables because of this?

I would say: It is a basic ability of a database developer to keep track of large amounts of data and to have all processing including queries executed quickly enough so that the user does not experience any problems. You can learn this basic skill and thus avoid a lot of workarounds, which can bring with them a variety of problems and causes of errors.
Actually i open this scenario just open the big picture of possibilities on how to accomodate this concern. I observed topics concerning deletion and one experience here told that he is not agree about deleting data instead it must be stored in archive table. Now, for the seek of argument i open here since this the forum which we can share knowledge and experience. We cannot argue if our client need for that possibilities if can do instead of being defensive rather than to solve? shall i tell them to think first before you said that.
 
must be stored in archive table
It will also be good practice to create backups based on the need for data currency - because data is the most valuable asset. Indirectly deleted data records can be determined via backups.

So whether I need additional archive tables for deleted records would be a question of more direct and faster access to them. So I ask myself the question again: what for and how often do I need deleted data?

Most databases are reservoirs. There is collected and nothing thrown away, even throwing away information is information in itself. You can also handle larger amounts of data because the entire processing structure and processing methods are designed and optimized for this. And then a deletion note in the data record is sufficient without ever having to actually carry out a real deletion. A detailed deletion note could be presented in a time stamp and a foreign key on the reason for the "deletion".

We cannot argue if our client need for that possibilities
Yes, we should. The developer must also advise the customer, not just blindly implement wishes, wishes whose scope and effects the customer often does not know or cannot estimate. The customer wants a working product.

open the big picture of possibilities
Consider my statements as an enlargement of the overall picture.
 
Last edited:
I would say: It is a basic ability of a database developer to keep track of large amounts of data and to have all processing including queries executed quickly enough so that the user does not experience any problems. You can learn this basic skill and thus avoid a lot of workarounds, which can bring with them a variety of problems and causes of errors.
in any organizations, there is a permitted time (how many years) of historical data can be kept.
after that period records can be safely destroy.
these are dormant data and mostly inactive.
it need to be purged.
 

Users who are viewing this thread

Back
Top Bottom