I'm trying to make a excel macro to find a name in a table, let's say I want to find Mark, and want it with an input box, that one I know how to do:
InputBox("Qual o Nome?")
But I would like that there is a list to choice from, instant of having to write the name every time, so lets say the names are in Row C (let's say C4:C15).
After finding the name (imagine the name is in C5) I want it to select next column (in this case D5), and insert on that cell a value, that will ask in a new InputBox.
Right now I'm having some trouble doing the looking for the name and select new column cell according to the name position.
So this is what I got so far:
Private Sub CommandButton1_Click()
'This one i cant figure it out
Dim Range As Variant
Range = InputBox("Qual o Char?") 'Here is where i say the name
Cells(Range, 1).Value = InputBox("Focus actual?") 'Here i want it to insert in the cell right, after the name it looked for
Cells(Range, 2).Value = Now() 'Here i want it to insert in 2 cell right, after the name it looked for
End Sub
Your code will look something like:
Private Sub CommandButton1_Click()
'Declare the variables you will need to store the found range and two user inputs
Dim foundRange as Range
Dim userInput1 as String
Dim userInput2 as String
'get your user input into variables
userInput1 = InputBox("Qual o Char?") 'Here is where i say the name
userInput2 = InputBox("Focus actual?")
'Use the Found method of the Range object to find your userInput
foundRange = Sheet1.Range("A1:Z500").Find(userInput, lookin:=xlValues)
'Use Offset() to move around and place values:
foundRange.Offset(0,1).Value = userInput2 'Here i want it to insert in the cell right, after the name it looked for
foundRange.Offset(0,2).Value = Now()
End Sub
Likely some more work will be needed to validate your user input or do something different if Range.Find() comes up empty, but this should get you in the ballpark.
Related
So I am trying to change the value of cells in multiple sheets based on user input. The user inputs the column that they are trying to change and the value they are changing it to, the row will always stay the same. For some reason, I keep getting a subscript or object-defined error. Here is the code that I have so far.
Sub changeValue()
Dim column As Variant
Dim value As Variant
column = InputBox("Column:")
value = InputBox("Value:")
Worksheets("Sheet2").Activate
With Worksheets("Sheet2")
Worksheets("Sheet2").Cells(7, column).Value = value
End With
End Sub
Right now I am just trying to change the value in one sheet but I would like to extend this to multiple sheets. Thanks!
I'm trying to write a code that would look up a string value (that I would get from the user) from a table located in another sheet of my workbook.
I've tried using the Range.Find function as well as Application.WorksheetFunction.Vlookup.
Sub ID_Lookup()
Dim name As Variant
Dim FoundID As Range
Dim test_tbl As ListObject
Set test_tbl = Sheets("Sheet1").ListObjects("Full_List")
name = InputBox("Enter ID name:")
'Snippet used to find user input value above located in table from another sheet.
On Error Resume Next
FoundID = test_tbl.DataBodyRange.Find(name, LookAt:=xlWhole)
' FoundID = Application.WorksheetFunction.VLookup(name, test_tbl .DataBodyRange, 1, False)
On Error GoTo 0
End Sub
While the logic above seems to work well for numerical values, it returns an error (in case of Vlookup) and Null (in case of Range.Find) while trying to find string values.
The string values I need to lookup are sometimes a combination of letters, numbers and a period character (for example: AB.CDE2) and I have tried setting the user input to both String and Variant datatypes to no avail. The column from where I would search is also Text ('General' format in Excel).
Any direction would be helpful.
I have a large file that I am working on and need to be able to calculate people DOB. I have attached a sample file here to get an idea.... but basically what I am looking to do is ONLY if data exists in the "DOB" column, for "Age" to be calculated.
DOB will be listed in every other column for up to 18 different people (so column A, C, E.....) In columns B, D, F..... I am looking to have the age be calculated in years.
The catch is, there will NOT always be data for 18 people, so this is something that would only need to calculate IF data is present in the DOB column.
Ideally this would be a macro that I would run when I open the file so that all of the ages can update.
How do I even go about doing something like this?
I would expect output to just show age in years.... so if DOB was 01/01/2001 - age would show as 18
I'm going to make the assumption that VBA is overkill. This worked for me ...
=IF(A1="","",ROUNDDOWN(YEARFRAC(A1,NOW()),0))
If you were looking at a VBA solution, the above formula is translatable directly to VBA. It's not complete in relation to your context but that's a bigger piece that is hard to inject into without seeing your code at present ...
Public Sub WriteAgeToCell()
If Range("A1").Text <> "" Then
Range("A2") = WorksheetFunction.RoundDown(WorksheetFunction.YearFrac(Range("A1"), Now), 0)
End If
End Sub
Using Workbook_Open() in your Workbook object can be used to automatically recalculate what you need.
So to put it all together, and with a little bit of compromise, you can do the following ...
Private Sub Workbook_Open()
Dim objSheet As Worksheet, lngAgeCol As Long, lngEndRow As Long, i As Long
Dim lngStartRow As Long
With Range("rngHeaderAge")
Set objSheet = .Worksheet
lngAgeCol = .Column
lngStartRow = .Row + 1
End With
lngEndRow = objSheet.Cells.SpecialCells(xlLastCell).Row
For i = lngStartRow To lngEndRow
objSheet.Cells(i, lngAgeCol).FormulaR1C1 = "=IF(RC[-1]="""","""",ROUNDDOWN(YEARFRAC(RC[-1],NOW()),0))"
Next
End Sub
When the workbook is opened, it will fill down the formula from the row below the header column and then if DOB's are changed during the session, the age will update on the fly.
To make the above work, all you need to do is update the code into the Workbook object within the VBA editor and create a named range against the header for the age column, as shown below.
In a Worksheet_Change event routine, the target value is not of a specific cell but that of the range address of the pivot table that cell belongs to.
The code below is intended to detect if a certain named cell was created. If it wasn't then no action is needed. But if it was, then the value of that named cell will point to one less than the column of the cell that I want to detect changed, prompting a certain action.
I expect the change to occur in the value of a Report Filter field of a pivot table, which I fully expect to be in row 4, but at a column that is 1 more than the value of the dynamically-created named cell "cLeft" I checked the existence of.
I detect the change via a change event. However, instead of giving the address of the one cell that changed, I get the range address of the full pivot table. How can I get only the address of the cell that changed?
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Pos As String
Dim rNW As Long
Dim cNW As Long
Dim rSE As Long
Dim cSE As Long
On Error Resume Next
Pos = Range("cLeft").Address
If Err <> 0 Then
On Error GoTo 0
Else
Call GetCorners(Target, rNW, cNW, rSE, cSE)
If rNW = 4 And cNW = Range("cLeft") + 1 Then
.
.
<some action>
.
.
End If
End If
End Sub
Sub GetCorners(Rng As Range, rNW As Long, cNW As Long, rSE As Long, cSE As Long)
' Decode the upper left and lower right of the range into appropriate row and column values.
Dim ArR() As String
Dim ANW() As String
Dim ASE() As String
Dim RngStr As String
RngStr = Rng.Address(ReferenceStyle:=xlR1C1)
' See if the range is a single cell. If it is, replicate it at the end.
If InStr(RngStr, ":") = 0 Then RngStr = RngStr & ":" & RngStr
ArR = Split(RngStr, ":")
ANW = Split(ArR(0), "R")
ANW = Split(ANW(1), "C")
ASE = Split(ArR(1), "R")
ASE = Split(ASE(1), "C")
rNW = Val(ANW(0))
cNW = Val(ANW(1))
rSE = Val(ASE(0))
cSE = Val(ASE(1))
End Sub
I have a pivot table whose "Northwest" corner is always in row 4. Its column number can vary. In my example it is column 101. At the moment of creation of the pivot table I also create a named cell called "cLeft". In it I then record the number of the leftmost column of the pivot table, 101.
The pivot table has only one report filter for a field called "Status". The position of the filter is always in row 4 and column number equal to 1 + the value of cLeft. In the example, it is row 4, column 102.
I want to perform some additional action when the value of the filter changes. For that, I use the above code, but it doesn't work all that well because the value of "target" is not the address of the one cell that changes, R4C102, but the address of the whole pivot table, R4C101:R29C117, which also changes, depending on the selection.
How can I coax the address R4C102 out of the routine? I don't want to use Worksheet_SelectionChange because, although that gives me the answer I want, it requires me to select the cell holding the filter first, and then change the filter, a 2-step sequence I can't expect the end users to remember to do.
I want to do the following: I have a table = Listobject which has a column called MasterID. Some columns have the same MasterID and some have even non. I need to manually add the missing MasterIDs.
I want take a row where the MasterID is empty and then I want to click on the column MasterID and select an ID for this column. It can either be an existing ID. Which is the unique lsit of used MasterIDs in the hole listcolumn OR it can be a new MasterID. If a new ID is selected it should be the next integer from the biggest MasterID. So if the highest masterID up until now was 1000 then the new one should be 1001.
So I wanted to know if there is a way to use data validation in order to suggest me the next bigger MasterID or all existing. Since the already filled MasterIDs are randomly distributed I need to make this into a single formula.
Lets formulize this a little:
IF the cell is NOT EMPTY it can be whatever it wants to be, ELSE the cell needs to be one of the values used in the listcolumn OR the MAXIMUM of the Listcolumn +1.
If possible I would like to use a dropdown list.
I have tried this with a data validation list option but I couldn't figure out how. I know there needs to be a structur like this:
If Isempty then BeWhatever
Else Be DynamicAdjustedListofEntries OR MaximumEntry+1
I have thought of doing this with a macro but I don't want to update this everytime I change something. Can anyone help?
I don't think dynamically filling up the list type of validation is possible using pure Excel. Here's my solution using VBA. Place this macro in the appropriate worksheet:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
If Target.Column = Range("Table26[MasterIDs]").Column Then
Dynamic_Data_Validation "Table26[MasterIDs]"
End If
Application.EnableEvents = True
End Sub
Note: Change Table26[MasterIDs] according to your data.
Then paste this in a normal module. You can, of course, paste these lines directly into the Worksheet_Change procedure.
Sub Dynamic_Data_Validation(table_range As String)
Dim ids() As Variant 'Didn't declare as Long because JOIN function doesn't accept it
Dim row_count As Long
Dim src As Range, tmp_rng As Range
Dim validation_list As String
Application.ScreenUpdating = False
Set src = Range(table_range)
ids = src.Value
'Change X to some other column name if you don't prefer this
Set tmp_rng = Range("X1").Resize(UBound(ids))
tmp_rng = ids
'If sorted in descending order, it becomes difficult to add the
'(MAX + 1) ID in the beginning of the array
tmp_rng.Sort Key1:=tmp_rng, Order1:=xlAscending
tmp_rng.RemoveDuplicates Columns:=1
row_count = tmp_rng.End(xlDown).Row
'Add the (MAX + 1) ID to the end of the range and resize it
tmp_rng.Cells(row_count + 1).Value = tmp_rng.Cells(row_count).Value + 1
Set tmp_rng = tmp_rng.Resize(row_count + 1)
tmp_rng.Sort Key1:=tmp_rng, Order1:=xlDescending
ids = Application.Transpose(tmp_rng)
tmp_rng.Delete Shift:=xlToLeft
'Perhaps consider adding a code to save the workbook after this line,
'as pressing CTRL + END will move the cursor to column X or whatever you choose
validation_list = Join(ids, ",")
'The existing validation needs to be deleted, otherwise it raises error
src.Validation.Delete
src.Validation.Add Type:=xlValidateList, Formula1:=validation_list
End Sub
I've used the worksheet to place the array items temporarily for sorting and removal of duplicates, because this seemed easier. An alternative is to manipulate the array elements within the array itself and then passing it as an argument to VBA.Join.
Here's the output: