1

I tried in different ways to resolve this excel issue but didn't find any resolution. Hope someone out here will be able to resolve my problem. I have a spreadsheet consists of 20+ tabs and each tab is pulling data from different websites and all these data are consistent in format. I am trying to archive the data in another sheet named "Archive" when the source data changes.

Here is the VBA code I am using:

Private Sub Worksheet_Change(ByVal Target As Range)
    Application.EnableEvents = False

    If Target.Column = 3 And UCase(Target) = "2016." Then
        Cells(Target.Row, Target.Column).EntireRow.Copy _
        Destination:=Sheets("Archive").Range("A" & Rows.Count).End(xlUp).Offset(1)
    End If

    Application.EnableEvents = True
End Sub

I would really appreciate if someone helps me out here.

Community
  • 1
  • 1
Tulan
  • 11
  • 2
  • 2
    If the cells are getting updated by a formula then `Worksheet_Change` is of no help... – Siddharth Rout Aug 02 '16 at 14:12
  • Thank you for your reply @SiddharthRout. I feel there should be something that we can do about it. Just can't see the answer right around the corner. – Tulan Aug 02 '16 at 14:18
  • 2
    So are the values from the website being pulled using formulas? – Siddharth Rout Aug 02 '16 at 14:19
  • 2
    You need to qualify the `Rows.Count` with the spreadsheet as well, otherwise it's going to be using the ActiveSheet (or the sheet the `_Change` event is running on): `Destination:=Sheets("Archive").Range("A" & Sheets("Archive").Rows.Count).End(xlUp).Offset(1)`. Not sure if that is going to be *the* fix, but it will certainly help. – BruceWayne Aug 02 '16 at 14:23
  • How are these tabs getting the values? From a formula? QueryTable? – David Zemens Aug 02 '16 at 14:29
  • @BruceWayne I tested your suggestion. Still not working. I think I am not seeing something... Thank you though. – Tulan Aug 02 '16 at 14:42
  • @DavidZemens I am getting the values from web (Data from web). – Tulan Aug 02 '16 at 14:42
  • OK I think that's a QueryTable, and it's possible to make those respond to events... hold on, I may have answered a similar question recently. – David Zemens Aug 02 '16 at 14:49
  • http://stackoverflow.com/questions/36341741/excel-vba-after-data-import/36342211#36342211 – David Zemens Aug 02 '16 at 14:50
  • Thank you @DavidZemens. I just went through the post. I think, I am facing a different issue. Not the connection/refreshing. It's refreshing but I am not able to archive the data before refreshing. – Tulan Aug 02 '16 at 14:57
  • 1
    OK, If you want to archive *before*, then you need to do the `Copy` in the `_BeforeRefresh` event of the QueryTable, I've made revision to the answer below. – David Zemens Aug 02 '16 at 15:00
  • The OP in the other question had two problems: 1) controlling when the data refreshes, and 2) *doing something with it* after/before it refreshes. The second half of my answer, which I posted below, should describe how to do this. – David Zemens Aug 02 '16 at 15:02

1 Answers1

1

See This Answer where I describe how to make a Query Table responsive to events.

Relevant details quoted below, insted of the MsgBox you'll need to write some code to copy all of the data (e.g., using the ResultRange.Address property of the query table), if you need to copy the entire table to archive, then it would be like:

Me.cQT.ResultRange.Copy Destination:=Sheets("Archive").Range("A" & Rows.Count).End(xlUp).Offset(1)

If you need to conditionally loop/copy rows based on criteria, you'll need to write that code, e.g.:

Dim rng as Range
For each rng in Me.cQT.ResultRange.Rows
    If rng.Cells(3).Value = "2016." Then
        rng.Copy Destination:=Sheets("Archive").Range("A" & Rows.Count).End(xlUp).Offset(1)
    End If
Next

(Or something like that, I'm not exactly sure what logic you need to implement)

How to add Event Handler for QueryTable

Create a Class module named clsEvents_QueryTable (or you can name it something else, just be consistent in the rest of the code). Put this code, which will allow you to establish an event-handler for a QueryTable object, and the two events' procedures.

Option Explicit
Public WithEvents cQT As Excel.QueryTable

Private Sub Class_Initialize()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets(1)   '## Modify as needed
    
    Set cQT = ws.QueryTables.Item(1)  '## Modify as needed
End Sub

Private Sub cQT_AfterRefresh(ByVal Success As Boolean)
    '###
    '   Code placed in, or called *from* this procedrure will run AFTER refresh
    MsgBox Me.cQT.Name & " has been refreshed"
    
End Sub

Private Sub cQT_BeforeRefresh(Cancel As Boolean)
    '###
    '   Code placed in, or called *from* this procedrure will run BEFORE refresh
    MsgBox Me.cQT.Name & " Archiving Before refreshing..."
    Me.cQT.ResultRange.Copy Destination:=Sheets("Archive").Range("A" & Rows.Count).End(xlUp).Offset(1)
End Sub

Put this in the top of a standard module:

Public QT As clsEvents_QueryTable

In your ThisWorkbook module, do this:

Option Explicit

Private Sub Workbook_Open()
    If QT Is Nothing Then
        Set QT = New clsEvents_QueryTable
    End If
End Sub

(You could do that in some other module, but this is just an example).

Now the table has the two event-handlers, and any time the QueryTable is refreshed, it will automatically invoke the code which is included or called from the event handler(s).

You can extend this to handle multiple QueryTables with some modification (using a collection of object, instead, etc.).

Community
  • 1
  • 1
David Zemens
  • 53,033
  • 11
  • 81
  • 130
  • Nice answer. However, the it's still not clear if the OP actually has QueryTables. – RBarryYoung Aug 02 '16 at 15:05
  • @RBarryYoung OP said "Data from web" which to me suggests he's using the "From Web" option on the "Data" ribbon, which creates a QueryTable object on the worksheet. – David Zemens Aug 02 '16 at 15:07
  • 1
    No, I get that, it's just that there's more than one way to get "data from the web", as I have found out after being called in to fix various legacy spreadsheets for customers. QueryTable is definitely the preferred way. (note: I am not the downvoter, and my comment was not trying to explain a downvote) – RBarryYoung Aug 02 '16 at 15:10
  • I just tested that and it's still not working for me. Or may be I am doing something wrong. But I really appreciate your help @DavidZemens. I actually found something in YouTube which solves the same problem but instead of archiving based on specific value how do I archive when any value changes? [https://www.youtube.com/watch?v=DpU8cNeD4CY] YouTube link. – Tulan Aug 02 '16 at 15:59
  • You'll have to save/close/reopen the file, or run the `Workbook_Open` event manually, otherwise the QT event handler won't work. If that still doesn't help, can you update your original question to include ALL of the code you're currently using? – David Zemens Aug 02 '16 at 16:01
  • If you're concerned only with values that have *changed*, you'll need to first store the values somewhere (an array, a new/temporary worksheet, etc.) and do a comparison against the cached data before you copy/paste. – David Zemens Aug 02 '16 at 16:03