Excel VBA - Timestamps for all Modifications to Rows in Multiple Tables - vba

I'm trying to add timestamps for any modifications made to all rows in a table. I have been able to find/modify some code that will add the timestamp, but it does it for every cell in that column. As you can see it's got a line that tells it to start below a certain row. I want to make this apply only to the tables in each worksheet in my excel file. This would include any new tables added to the sheets. I'm very new to VBA, so any and all constructive help is welcome!
A little background: These sheets are being used for resource forecasting for my company for every different project we have going on. And every crew in each project has their own table. The forecasts get updated each week. I want to be able to quickly find what has changed when I get these at the end of the week. This isn't meant to be a permanent solution for our forecasting needs, but it will make my life easier in the meantime.
This is the code I've been working with. As I mentioned I know this only does part of what I want. I was trying to modify it to do what I want, but I just don’t have the know how yet:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim r As Range, c As Range
Const DateStampColumn As Long = 2
'Date stamp column number
For Each r In Target.Rows
If r.Row > 10 Then
For Each c In r.Cells
If Not IsEmpty(c) Then
Application.EnableEvents = False
Cells(r.Row, DateStampColumn).Value = Date
Application.EnableEvents = True
Exit For
End If
Next c
End If
Next r
End Sub

I was able to modify it to do what I needed. I removed the message box lines because I think that will frustrate the users entering the data (I'm the one that has to extract it). There is one issue that I'm hoping you could help me solve. Whenever I add or delete a row within the tables a timestamp appears. Is there a way to keep that from happening? Here is what my code looks like currently:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim t As ListObject
For Each t In ActiveSheet.ListObjects
If Not Intersect(Target, t.DataBodyRange) Is Nothing Then
Application.EnableEvents = False
Cells(Target.Row, "B").Value = Date
Application.EnableEvents = True
Exit Sub
End If
Next t
End Sub

You need something along these lines I think. This checks whether Target is in a table, I haven't added the Date as I'm not sure where it should go.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim t As ListObject
For Each t In ActiveSheet.ListObjects
If Not Intersect(Target, t.DataBodyRange) Is Nothing Then
MsgBox "Cell changed in " & t.Name
Exit Sub
End If
Next t
MsgBox "Cell changed not in any table"
End Sub

Related

VBA code to autoupdate cell with current date, when cell changed, not working

I have a sheet where I daily change the stats of some rows and I have to know when the stats changed. To make my life easier, I found on the internet this VBA code:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("R1:R2000")) Is Nothing Then Exit Sub
Target.Offset(0, 1) = Date
End Sub
The code works wonderfully. Everytime I change de stats on column R, it update the date on column S.
The problem is that I change this stat in a table linked to an outside source (Oracle Database) and if I try to refresh the table, it change the entire content of the table to different dates. What I have to do now is, everytime I have to refresh the table, I just comment the entire VBA Code.
Is there anything I can change on the code so it doesn't update when I refresh the table?
Edit 1:
Sub RefreshOracleTable()
Application.EnableEvents = False
If Intersect(Target, Range("R1:R200000")) Is Nothing Then Exit Sub
Target.Offset(0, 1) = Date
ThisWorkbook.Sheets("wsTables").ListObjects("OracleTable").QueryTable.Refresh BackgroundQuery:=Application.EnableEvents = True
End Sub
Disable events, then refresh table
You can write a Sub, which you will use for refreshing the table. Before refresh you will disable excel events. Like so:
Sub RefreshOracleTable
Application.EnableEvents = False
'the refresh itself code something like
Thisworkbook.Sheets("wsTables").ListObjects("OracleTable").QueryTable.Refresh BackgroundQuery:=False
Application.EnableEvents = TRUE
End Sub
Manual entry of a Date with Keyboard shortcut
Consider using a Keyboard shortcut to manualy enter the current date. CTRL + ;
Explanation of current situation and proposed solution

Hide Active Column when cell value is changed

I have been trying to work this out myself for the last few days and caught myself in a bit of a one step forward three steps back cycle. I've been reluctant to bother you thinking this would have been answered somewhere else before now.
The idea is that I have a spreadsheet that has criteria in rows with separate entries in rows; in row 6 it is the status of each column entry, which when changed to "Completed" I would like the column to be hidden.
I've been floundering around with Worksheet_Change and been able to hide specific columns, but not the active column.
Any help offered would be much appreciated and I'm sorry if this has been covered elsewhere, but I've not been able to successfully apply any examples out there.
Thanks.
Whenever you have to work with worksheet_change events, you have to consider a cycle for it, due to user may delete multiple data at the same time or do a copy paste, if you only consider "Target" It would give a debugger error.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ItemMultipleData As Range
For Each ItemMultipleData In Target 'handles multiple cells, paste, del, etc
'your code (instead of using "Target" change to ItemMultipleData. IE:
'If ItemMultipleData.Value = "Completed" Then
Next ItemMultipleData
End Sub
Here is a starting point. It only checks row # 6:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng As Range
Set rng = Range("6:6")
If Intersect(Target, rng) Is Nothing Then Exit Sub
If Target.Count <> 1 Then Exit Sub
If Target.Value = "Completed" Then
Application.EnableEvents = False
Target.EntireColumn.Hidden = True
Application.EnableEvents = True
End If
End Sub
EDIT#1:
This approach assumes that only one cell at a time is being changed........that makes it easy to "find the active cell"

copy row to next free row on another spreadsheet on change

First off, I'm a noob when it comes to Macros and VBA, so please forgive me if I don't make sense.
I've got an Excel spreadsheet which is basically a list of users and their mobile phone numbers and some other bits (columns A-K are currently used) and it's ordered by rows.
What I need is a way of copying the whole row if I change a cell. So if I change the username, it copies the whole row of that user to the next blank row on a second sheet.
The purpose of this is to keep an audit trail allowing us to see who's previously used a number etc.
I found this: Copy row to another sheet in excel using VBA which is working as intended, but I can't for the life of me get it to a, copy the cells to the next free row, or b, not overwrite the existing entry.
This is the code I'm using:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim a As Range, rw As Range
For Each a In Selection.Areas
For Each rw In a.Rows
If rw.Row >= 2 Then
rw.EntireRow.Copy Sheet2.Cells(2 + (rw.Row - 2) * 3, 1)
End If
Next rw
Next a
End Sub
I'd really appreciate it if someone could help me customise it.
I'm using Excel 2010 on Win7.
Many thank in advance.
Typically the Intersect method is used to determine if the cell or cells receiving a change involve one or more columns that you are concerned with. You can add additional parameters; in this case, I've .Offset the Worksheet.UsedRange property down one row to make sure that row 1 is not involved.
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Columns(1), Me.UsedRange.Offset(1, 0)) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False 'not really necessary in this case but never a bad idea within a Worksheet_Change
Dim a As Range
For Each a In Intersect(Target, Columns(1), Me.UsedRange.Offset(1, 0))
If CBool(Len(a.Value2)) Then _
a.EntireRow.Copy _
Destination:=Sheet2.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0) 'not really sure this is the correct destination
Next a
End If
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
I've included a call to disable event handling for the duration of the Worksheet_Change event macro. While this is a critical step when the Worksheet_Change modifies values, it is not really important to incorporate here. However, it does not harm and is already in place in case you want to augment the Worksheet_Change to include something like a timestamp that would change the values on the worksheet.

Excel date formatting error

I'm doing some work on an already done excel program, but I'm very rusty in this area or probably never had done something in this part, I'm very new in VBA so please don't judge me if it's a simple mistake or error the links are in the description.
So I have problem where if I put the confirmation option, for example: in one cell press "1" in the product you have, and in another cell write "S" if you already have the product and it puts you a date of today in another cell.
The problem is when I delete the info that I inserted, and reenter it the date deformats itself becoming smaller and the location on the cell changes too.
I'm going to put the links because, like I said I'm rusty and I can't find where the code of this date comes.
http://www.docdroid.net/12dh4/master-atual-20155.xls.html -->This one is the Excel
http://www.docdroid.net/12dhj/errorphotos.pdf.html --> photos showing error
this is the code of one of the sheets the other ones are almost the same, If you guys see the photos it would help to understand the error itself.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rng1 As Range
Set rng1 = Intersect(Range("v3:v500"), Target)
If rng1 Is Nothing Then Exit Sub
Application.EnableEvents = False
On Error Resume Next
If rng1.Value <> "" Then
rng1.Offset(0, 2).Value = Now()
Else
rng1.Offset(0, 2).Clear
End If
Application.EnableEvents = True
End Sub
The code would be triggered when you do the changes at column V. You may find the code in the worksheet itself:
it will clear the date if the column V contains no value.
By the way, the date is not getting smaller but it show the date of today in different format. you may check the date format by right click the cell and choose the format cells... option to look at it.

Excel macro select two ranges and compare

This is a question that was asked to me in an interview. I have a excel list. It is copied to another location and then by mistake a row in the new location gets deleted.
Now I need to write a macro to compare the old and new ranges and then provide the missing data as result.
I can perhaps perform the comparison part. But the problem is I don't know how to get the selected range as input in a macro.
For eg. as soon as I select a range, it should be sent as input to the macro, then the macro should wait for another selection. As soon as I select the new range, the macro should compare and find the missing lines in new range.
Regarding the selection per mouse click you could look at the link I sent in the comments of the other answer. Selection_Change is an event which gets triggered when you change the selection of a worksheet (not only mouseclick but move-by-keys as well). The target coming in is the cell which you have selected. You can pass this as a range on to a function.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
showMsg Target
End Sub
Private Function showMsg(r As Range)
MsgBox r.Address
End Function
You can just as well use another event like BeforeDoubleClick or BeforeRightClick. Check out the events of Excel and choose the one you feel fits best.
If you only want the function to be triggered for a certain range you can filter it.
If target.column <> 1 then exit function
If you don't want the event to trigger your function each time you change a selection you can choose one cell to be the switch which gets triggered by the same event.
If target.address = "$A$1" Then Call toggleSearch()
with toggleSearch being the switching function.
This is a classical diff (and a simple one at that), you shouldn't select by hand or anything. Just sort the two lists in an identical way, then run a Sub which loops over the number of rows in the source sheet comparing each row with the same row in the target sheet. The first mismatch you get is the missing line.
This example assumes both sheets are in the same workbook but you can easily adapt it
Public Sub diffThem()
Dim src as Worksheet, trg as Worksheet
Dim r as Range, i as Integer
Set src = ThisWorkbook.Sheets("Source")
Set trg = ThisWorkbook.Sheets("Destination")
Set r = src.Range("A1")
For i = 1 to ThisWorkbook.Sheets("Source").UsedRange.Rows.Count
If r.EntireRow <> trg.Range("A" & r.Row).EntireRow Then
MsgBox("The missing row is " & r.Row)
Exit Sub
End if
Set r = r.Offset(1,0)
Next i
End Sub
If EntireRow cannot be run due to different layouts or whatever then loop the columns at that point.