VBA Range statement using active column - excel

I need to use my active column in my range statements. How to write down this:
Range((Activecolumn)2)
So I need a column value to be dynamic because I am moving left and right by pressing a userform button, but the row number always stays the same. At first I am working with column "C" and select it with
Columns("C").Select
and I navigate the selected column with
Private Sub Next_Format_Button_Click()
ActiveCell.Offset(, 1).EntireColumn.Select
End Sub
So when I navigate to the next column I need all my other range statements to go along with it. So basically the column letter in my range statements should be something like "current" or "active" column.
Could someone, please, help me?

Range(ActiveCell.address).entireColumn.copy
Is what you are looking for I think?
I'd also recommend avoiding ".Select" unless absolutely necessary. It is adding unnecessary lines to your code and leaves the program at greater risk of inadvertent user corruption by selecting another range via mouse before the copy (or whatever) operation completes. Better to go straight to whatever operation you intend to do, or by assigning the range to a variable.
edit: Ah, sorry, I see now your only looking row 2, then its Cells(2, ActiveCell.Column) as pointed out above.

If you want to get the Number of the column where you selected something:
ActiveCell.Column
If you need the letter of the column your selection is in:
Split(ActiveCell.Address, "$")(1)

Related

How to look through a sheet and find a value, get the column, and then count how many times a value appears in that column

I am working with data that is sent to me. The sheets always contain the same headers though they aren't really headers because it doesn't come in table form, but the columns change every pull so it is never in the same column so I can't do the Index Match like I'm used to. I need to get this to work without converting the data to a table because others that use this don't know how to do that. Is there a way to search the sheet to find the cell containing the value, capture that column address, and then count how many times the column contains a letter?
I have a front excel page that keeps account of how many times something happens. Currently I use this formula =COUNTIF('UDO '!AJ:AJ,"Y"). It works the only thing is that I can't set it up as an array because the column isn't always AJ, so I'm always having to change it manually and I'd like to automate it. So I want to be able to search the sheet that contains the information for the text value example: "Review Required FY*" and get the column that contains this (it should be a unique value) then I want to look down that column and countif it has a "Y" or "y" marked in the cell. The sheets are always varying in length and column numbers. I thought about using an HLookUp but I can't get it to work. I also could not get Index Match to work, because I never know how much data or the column order the Audit tab will be in or have.
So on the Main tab I have a cell that counts how many files I have to audit I want to go to Audit tab, look for "Review Required FY*", capture that column and count how many times "Y" or "y" are there. I'd like to be able to set this up to do it all by itself.
I currently do not have any code because I can't find anything that works.
Using VBA
Option Explicit
Sub Looper()
Dim ws As Worksheet, Found As Range, LR As Long
For Each ws In Worksheets
Set Found = ws.Cells.Find("Review Required FY*")
If Not Found Is Nothing Then
LR = ws.Cells(ws.Rows.Count, Found.Column).End(xlUp).Row
MsgBox Application.WorksheetFunction.CountIf(ws.Range(ws.Cells(1, Found.Column), ws.Cells(LR, Found.Column)), "Y")
End If
Set Found = Nothing
Next ws
End Sub
Assuming the header only appears once, you can find out what row your header is in you can use an array formula like this (apply using Ctrl+Shift+Enter):
=MAX(ROW(A1:A10)*COUNTIF(OFFSET(A1:Z1,ROW(A1:A10)-1,0),"Review Required FY*"))
(looks in the first 10 rows across A:Z)
You can feed the result of that into a lookup to find the column number.
EDIT - something like this:
The first formula needs to be entered using Ctrl+Shift+Enter but the other 2 do not.
The 1000 in the last formula is a best guess at how much data there might be below your header - no problem setting that much larger to be on the safe side, as long as you don't try to count past the end of the sheet.

How to select cell range dynamically in sumproduct in excel

I am trying to use Sumproduct dynamically on a sheet that will be updated regularly.
My motive is to not manually select the columns ( i.e. not to use the shift key and down key to select the range A2:A6 as seen in the attached snapshot)
I want to have the formula "=SUMPRODUCT(--(A2:A6="TX"))" pick up the A2:A6 dynamically since my data in worksheet say A is everchanging. So that when the data has grown to A8, it can be somehow picked up dynamically than manually using the keys.
Can this be done? Please let me know if my question is not clear.
Screenshot of my xls
Regards
SM
Yes, you could define the range dynamically. However, given your current formula, I see no reason why you should not switch to COUNTIF here, i.e.:
=COUNTIF(A:A,"TX")
a function for which the use of entire column referencing (A:A here) has no detriment to performance (which is not at all the case with SUMPRODUCT).
Regards
Shitty recommendations guy, here.
Can you insert a new line above all in your sheet? You could put it really wherever you want and you can even hide it, the first line just works for me.
If you can, just make it an "count.values" function on the entire column with an appropriated subtraction to adjust the count to the right length of your data. E.g. Removing this auxiliary cell value plus a header would be "=count.values(A:A)-2".
Later, on your VBA, you could retrieve this value to a variable and concatenate it to your main function. Lets say you made the auxiliary on cell A1 (coordinates 1, 1)
Dim auxLine As Integer
auxLine = cells(1, 1).value
whatever.formular1c1 = "=SUMPRODUCT(--(A2:A" & auxLine & ="TX"))"

Need logic for checking range in formula

Need help with logic. I have about 1000 rows of data where formulas were entered to calculate subtotals and totals. The nature of the formulas require each respective range to be correct. The correct range is determined by data in column C (please see illustration). For the most part, the ranges (and in turn the formula) are correct. But I have reason to believe a handful are not.
I can check them all manually or I can ask SO for help ^_^ My current thought is to loop column A and at every Subtotal, dump the rows counted so far into column V and pull the rows in the formula from column G into column W then compare V and W.
But what do I do when I reach a Total? My current thought would become cumbersome. Is there a better way? All the highlighted 0s between columns i:u need to be tested as well.
I will entertain solution to replace all formulas from scratch as well.
I'm not sure if this is what you are looking for, but I wanted to run it by you as an idea.
This example will put the totals from column G into Column Z.
Anyway, check it out, if you don't like it, I'll get rid of it.
You can add another line or make up a loop to get all the columns total.
Sub Button1_Click()
Dim RangeArea As Range
For Each RangeArea In Columns("C").SpecialCells(xlCellTypeConstants, 1).Areas
Cells(Rows.Count, "Z").End(xlUp).Offset(1).Value = Application.Sum(RangeArea.Offset(, 4))
Next RangeArea
End Sub

In VBA, looking to write a script that will carry out a function if a cell contains certain text, with ranges set as columns

I have a long string of data with lots of columns. The columns all have names like "Person_1_Date", "Person_1_Name," "Person_2_Name," Person_2_Date" etc.
I'm trying to write a script that will take the titles for each person (Person_1, Person_2), etc. and re-arrange them in a particular order (Date, Name, Date, Name, rather than Date, Name, Name, Date, as it is here).
The rough partial script I'm experimenting with looks like the following so far:
Sub Test()
Dim Rng As Range
Dim k As Long
Set Rng = Columns("B:B")
For k = Columns("B").Column To Columns("DE").Column Step 1
If (IsNumber(Search("Person_x_Date", "k" & 1)) Then 'Looking to make this get called if the Search comes back with a number'
Columns("k:k").Cut
Rng.Selection.Insert Shift:=xlToRight
Next k
End Sub
A few things I'm looking for help with. Is it possible to write a Search function that will look for parts of what's in a cell, while ignoring another? With Person_x_Date I'm hoping it to find a cell with anything in place of the x, so it could find Person_1_Date, Person_2_Date, etc. Is this possible?
The rest is a bit of a mess. Essentially, I want to set a range as a whole column, and if the search finds something, it'll copy and paste it into the correct place, and continue again until it finds what should come next (Like Person_X_Date).
I know the latter part of the code I wrote is quite far from that. I'm just looking for any kind of suggestions to help me put this together.
Be aware that excel sorting can be done horizontally (most people just use it vertically).
This in effect allows you to sort columns into order based on values in a row. (Normal vertical sorting will sort rows based on a value in a column).
In the sort dialogue, click the options button to choose horizontal sorting.
I think this will actually give you what you need.
however, if you need to manipulate the data values, you could create a formula row that changes the values and then sort on the data in the formula row..

How to use relative names in Excel VBA

Many "advanced" (aka: VBA) excel tutorials on the web or even excel's vba help encurage us to use the
Range("B2:B10")
method (to be precise: object) for selecting cells or getting values. In the same place they often add it's totally ok to use predefined names as well:
Range("valuesabove")
On the other hand I fell in love with the incredible power of relatively defined cell names. They make it so much easier to write and handle big composite formulas, and basically to refer to nearly anything.
However, relative names don't work in the Range("valuesabove") method the way we are used to it.
Usually (when used on the worksheet) relative names are relative to the currently selected cell or to the cell in which they are used.
In VBA's Range() object this is not true. Range is relative to a WorkSheet object, by default to the ActiveSheet. But ActiveSheet is represenetd by its leftupper cell, A1. And this is what Range turns out to be relative to. And this is why absolute names ($C$23) do work with it, and relative ones ("one column to the left, two rows up") don't.
So my question is:
How can I harness the power of relative names in VBA then?
EDIT:
Realising that my question was rather unclear (thx's go to you guys commenting tirelessly) let me try to put it in a specific form and clarify terms:
IMHO on an excel worksheet it is very comfortable to use names in order to refer to cells or define calculated values by functions based on cell values.
In excel a reference to a cell can be either relative, absolute, or mixed. This is true also when creating names. Thus we can speak about absolute, relative or mixed names (in terms of referring of course).
Here an absolute name is used a couple times (created using excel's Trace Dependents function):
Name "name" = $D$2
A relative name is used a couple times here:
Name "upright24" while, e.g. cell A7 is selected = C3 (without $ signs!). But this changes constantly according to the selected cell or region. You can check it in the name manager! (Ctrl+F3)
And this is what we can consider as a mixed name:
Name "rel_serialnumber" while, e.g. cell C6 is selected = $B6. The row of which (6) changes constantly according to the selected cell or region.
The creation of a relative or a mixed name is explicitly based on the active cell at the moment of creating the name. The creation of an absolute name naturally doesn't rely on the cursor position.
Note, that
absolute names mean a dinamic offset from the referenced cell, which is one and only
relative names mean a static offset from the referenced cell, which thus changes always corresponding to the place where the name is used
mixed names mean a mixed (or half-dynamic) offset from the referenced cell, the row or column of which thus changes always corresponding to the place where the name is used while the other remains always the same (the offset in one or the other direction remains zero).
Okay, now here is the thing. I have a database-like excel sheet where I handle the rows like records and the columns as fields for properties. The user uses this thing as follows: he "selects a record" by placing the cursor in any cell of the row of the desired record. Then he presses a big command button which starts my VBA macro. This intends to open a prepared skeleton file and fill some specific cells in it (which are btw defined by absolute names) with some values (which are defined by mixed names) from the selected record.
Since Range("name") is considered ok to use in VBA (see above) I thought Range("relativename") or Range("mixedname") will work just as fine while automatically relying on the active cell.
I couldn't be worse.
Only Range("absolutename") works in the way one would expect! Explanation see above.
So I'm after a function / method / object that is possibly as comfortable to use with a "relativename" or a "mixedname" as Range("absolutename") is.
It appears you are looking for Range.Offset() http://msdn.microsoft.com/en-us/library/office/ff840060%28v=office.15%29.aspx
However you could do it as:
'Your example Range(Col_B_in_current_row) as
Range("B" & ActiveCell.Row).Select
'Your example Range("B2:B10") -> Range("valuesabove") as
Range("B2:B10").Offset(-1, 0).Select
Just seems like a relatively simple syntax already exists for this.
I think I've found a proper and compact solution. It's
Names("mixedname").RefersToRange
Not as short as Range("mixedname") would be but it is really providing the expected values.
UPDATE:
This solution is mostly unuseful if you want to copy relative-named cell values in a source workbook to relative-named cells in a dest workbook with a single codeline. This is because Names() relies on the actual position of the cursor which is depending on which workbook is currently the active one and in most cases this won't be ok for the other.
In this case the non-fixed part of the name has to be stored:
sourcerow = ActiveCell.Row
[...]
'opening a wbk, this also makes it the active one
[...]
Names("dest").RefersToRange = mysheet.Cells(sourcerow, mybook.Names("src").RefersToRange.Column)
To reference a Range relative to another Range you can use this syntax:
myRange.Range("namedRange")
Note: This only works if both the Row offset AND the Column offsets are positive. For example if the "Refers to" formula for the named range is "=Offset(A1,r,c)", then the above syntax will throw an error if Either r Or c is negative. But, it will work if both are positive.
The asymmetry is unfortunate but business as usual for VBA...
To Reference the third column in the row of the current ActiveCell:
ActiveCell.EntireRow.Range("C1")
To reference a cell offset by (for example) 1 row and 3 columns relative to the ActiveCell:
ActiveCell.Range("C2")
Obviously, you can use the same syntax with the Selection Object or any other Range value in VBA.
Private Sub Worksheet_Change(ByVal Target as Range)
If Not Intersect(Target.Address,ThisWorkbook.Sheets('sheetname).Range('RangeName)) Is Nothing Then _
'Do whatever you want down here.
ThisWorbook.Sheets('sheetname).Range('RangeName).Offset(0,Target.Row)
End If
End Sub
This should send you on the right path to what you want (which is super unclear). Use the worksheet change event to bring in user worksheet selections and changes into VBA modules. Put it into the relevant sheet.
I had the same problem, but I did get it to work - sort of. I don't know what is different about the simple example below, but it works. At first I thought selection mattered, but no - it works without changing the active cell.
(I still can't get it to work in my main spreadsheet.)
Named range: "TestName" = Sheet1!$H1
Values in H1:H10 = 1,2,3,4,5,6,7,8,9,10
Sub Test()
Dim x As Integer
For x = 0 To 10
Range("A1").Offset(x, 0).Value = Range("A1").Offset(x, 0).Range("Testname").Value
Next x
End Sub
Result: A1:A10 = 1,2,3,4,5,6,7,8,9,10

Resources