Excel dynamic column reference for range - vba

This seems like such an easy thing but I can't seem to work it out.
All I am looking to do is have a dynamic last column based on the last active column in the row above.
I have a similar code for finding the last active row
LastCell = Sheets("CALCULATIONS").Range("A20000").End(xlUp).Row
Sheets("CALCULATIONS").Range("A2:A" & LastCell).Copy
Now I am trying to work out a horizontal version.
All I want to do is find the last active column based on values in row 15 in CALCULATIONS
then drag the array formula that already in A16 across to [?]16 (? being the last column from row 15)
I feel like the solution is right in front of me but I've been drawing blanks!
Any help would be great!!

Try,
dim lc as long
with workSheets("CALCULATIONS")
lc = .cells(15, .columns.count).end(xltoleft).column
.range(.cells(16, "A"), .cells(16, lc)).formula = .cells(16, "A").formula
'alternate method
'.range(.cells(16, "A"), .cells(16, lc)).fillright
end with

Related

Sum a range from another worksheet

I'm trying to get this cell to total a range from another worksheet but I keep getting stuck. The range rows and columns vary but the starting point is always C2. I need to total from C2 to the rest of the used range (aka exclude columns A and B as well as row 1 but include everything else).
Please help if you can.
Range("A1").Formula = "Wage Totals"
Range("A2").Formula = "=SUM(" & ActiveWorkbook.Sheets("Wage").Range(Cells(2, 3), Cells.SpecialCells(xlCellTypeLastCell)).Address(False, False) & ")"
Check out this link Using SUM() in VBA
You can use that idea to change your code to:
Dim lastCol As Long
Dim lastRow As Long
lastCol = Sheets("Wage").Cells(1, Sheets("Wage").Columns.Count).End(xlToLeft).Column
lastRow = Sheets("Wage").Cells(Sheets("Wage").Rows.Count, 1).End(xlUp).Row
Range("A1").Value = "Wage Totals"
Range("A2").Value = WorksheetFunction.Sum(Sheets("Wage").Range(Sheets("Wage").Cells(2, 3), Sheets("Wage").Cells(lastRow, lastCol)))
This is pretty naive solution tho becuase it assumes the usedrange limits can be found by looking for last used row on Col "A" and last used col on Row 1. You can change that method of finding the limits.

CurrentRegion.Row.Count returns incorrect number

I have a column that contains question numbers and blank cells. For a specific set of questions I need to do calculations that are different from the calculations required for the rest of the workbook. Therefore I set out to identify that specific range, as it is not fixed in either start or end position.
Using a simple loop over column A I'm able to match against the text that is always contained in the first row of the specific area I'm interested in.
Now the amount of rows that follows is variable. The upside is that its always followed by an empty row.
So I thought to make use of the vba equivalent of ctrl+shift+down Cell(startrow,1).CurrentRegion.Rows.Count
This however doesn't return the correct result, 23 instead of 21.
When I do the ctrl+shift+down manual, it does select the right set of cells.
I decided to play around a little, and it looks like it takes two cells above the start cell to be included into the CurrentRegion, those cells are blank too.
Is there an alternative way to count the number of continous cells that contain data from a given start cell, without looping through all cells?
Edit: Some sample data:
row# - Cell content
71 - blank
72 - "xx" 'Match for startrow
73 - 1
74 - 2
.......
92 - 20
93 - blank
94 - blank
95 - "xx" 'next block of data.
I have a way to find the start row, so then Range("A72").CurrentRange should be 72 to 92, ie 21 rows.
After re-reading the question I noticed you have blank cells above what you are trying to count, rendering my lastrow count useless. You could always find the start position, end position, and calculate the number of rows between the two.
Just as an example:
startRow = Range("A1").End(xlDown).Row
lastRow = Range("A" & Rows.Count).End(xlUp).Row
rowCount = (lastRow - startRow) + 1
This goes from A1 downward, until it finds the first nonblank cell and stores that row number in the variable startRow. Then, it does what I originally stated, pulls the lastrow and stores that value in lastRow. Lastly it will just calculate the difference between the lastrow and the startrow. If the first value is a title of somesort, and you do not want it counted then remove the () + 1, but typically that'll be required in this situation to get a full count of the rows in that range.
Edit -
Per your comment, you have the startRow, and you are not interested in seeing the last row of the workbook - but instead are interested just in the range of cells after your startRow. Another option you may have would be using .Find on a full range of cells (starting with your start row). For example:
startRow = Range("A1").End(xlDown).Row
lSheetRow = Range("A" & Rows.Count).End(xlUp).Row
With Sheets("Sheet1")
lastRow = .Range("A" & startRow & ":A" & lSheetRow).Find(What:="", _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlDown, _
MatchCase:=False).Row
End With
RowCount = lastRow - startRow
Now, what this is doing is exactly what I said before. Finding your start row (which you already have) and storing it as startRow; then finding the last row of the sheet (which you already have) and storing it as lastRow. This is going to be the range that we look in. Realistically you don't have to do it this way, I just wanted to incorporate the variables I already had.
Then with whichever sheet you are doing this with (change naming conventions based on your workbook) it is storing a new variable, lastRow equivalent to finding the first blank cell within the range we are choosing. In this case it's searching inbetween the Start Row and the Last Row of the sheet. Then, it's subtracting the Start Row from the newly determined Last Row (or first blank row after your start row) and is showing how many continuous cells of data there are.
I created a new workbook and enterted your data into it, the RowCount variable was stored as 21.
I found out what the problem was. The current region is limited by completely blank rows or columns. Whilst my cell A71is blank B71is not, nor is A70. So starting at A72 by definition also includes A71and A70, hence the incorrect results. Now going to insert a blank row above the start row to make accurate calculations.

Array Formula in vba code with coping the formula down

I work on the code that will calculate Array Formula basing on how many records is in the column N:N that is 11 columns earlier (offset 11). I want to use the formula with array that will use the parallel row from the column N:N and copy down until the last record in column N:N exist. However, for now, formula copies down basing on the first record only instead of taking the row in parallel:
With ThisWorkbook.Sheets("Sheet1")
TargetRow = 4
.Range("N4", .Cells(Rows.Count, "N").End(xlUp)).Offset(0, 11).FormulaArray = "=IFERROR(Name&INDEX(Names_Area,MATCH(RC[-11],Name&Name_Origin,0),2),"""")"
End With
I heard about fill down function or something alike but I am not sure how to insert it here.
How can I fix it so when the formula copies down into rows it takes the row in parallel and not all the time N4 (that is the first row of records).
I will appreciate any help.
I also want to mention that any other formula without array works and copies formula down basing on the rows in column N:N that are in paralell.
Try with .Autofill. something like:
With ThisWorkbook.Sheets("Sheet1")
TargetRow = 4
.Range("N4").FormulaArray = "=IFERROR(Name&INDEX(Names_Area,MATCH(RC[-11],Name&Name_Origin,0),2),"""")"
.Range("N4").AutoFill .Range("N4:N12")
End With
I have used an example end point of N12 for the autofill which you can adjust.
Though note you are actually going to column Y with:
.Range("N4", .Cells(Rows.Count, "N").End(xlUp)).Offset(0, 11)
So you may want to ensure you autofill and populate formula in the actual column you want to fill.
Maybe something like:
.Range("N4").Offset(0, 11).FormulaArray =
Reference:
https://www.mrexcel.com/forum/excel-questions/500971-how-copy-array-formula-down-vba-macro.html
you could also use
With ThisWorkbook.Sheets("Sheet1")
With .Range("N4", .Cells(Rows.Count, "N").End(xlUp)).Offset(0, 11)
.Cells(1, 1).FormulaArray = "=IFERROR(Name&INDEX(Names_Area,MATCH(RC[-11],Name&Name_Origin,0),2),"""")"
.Formula = .Cells(1, 1).Formula
End With
End With

Count the number of cells in a found column using VBA

I am pretty new to VBA and I have been fighting with creating one simple report for many days so I decided to inquire for some help. I will be really grateful for any tips you have or could point to any errors I might've made in my code.
I have the below piece of code (extracted from my loop). What I want to do is to create a list based on around 20 excel files that will have below stats:
name of the current tab inside the workbook
count of nonblanks in a column which name contains word "Difference" (always in row 7 but can be in different columns)
count from the same column but where cells are not blank AND different than 0.
For the last stat I didn't even start so you won't see it in my code but I would appreciate if you have any tips for this one too (which method best to use).
Windows("PassRate.xlsm").Activate
b = ActiveSheet.Cells(Rows.count, 2).End(xlUp).Row + 1
Cells(b, 3) = xlWorkBook.Worksheets(i).Name
xlWorkBook.Worksheets(i).Activate
Set Myrng = Range("B7:M9999").Find(What:="Difference", LookAt:=xlPart, SearchOrder:=xlByColumns, MatchCase:=False)
If Not Myrng Is Nothing Then
RowQnt = xlWorkBook.Worksheets(i).Myrng.Offset(9999, 2).Cells.SpecialCells(xlCellTypeConstants).count
End If
Windows("PassRate.xlsm").Activate
Cells(b, 4) = RowQnt
My problem is that the macro runs and works, but the result I get is the list of tab names but all counts are 0 and I cannot overcome this issue. For the line number 7 I've also tried the piece of code below which yields the same result.
RowQnt = xlWorkBook.Cells(Rows.count, Myrng).End(xlUp)
Is it possible that my problem is due to the fact that in the source files the column containing word "Difference" is sometimes two merged columns? Unfortunately, I cannot change that as these are some automatically generated files from another program.
xlWorkBook.Worksheets(i).Myrng isn't a valid Range syntax while you can simply use MyRng which you already set to a not null Range reference and already has both parent worksheet and workbook references inside it
but even Myrng.Offset(9999, 2).Cells wouldn't do since it references one cell only and not a range of cells
you need a Range(Range1, Range2) syntax, where both Range1 and Range2 are valid Range references to the first and last cell of the range you actually want to count not blank cells of
furthermore you could use WorksheetFunction.CountA() function instead of SpecialCells(xlCellTypeConstants) range, since this latter errors out if no constant cells are found in the range it's being applied to (so you'd need a check) while the former simply returns zero if no not empty cells are found
for all what above you could write the following GetRowQnt() function:
Function GetRowQnt(sht As Worksheet) As Long
Dim Myrng As Range
With sht '<--| reference passed worksheet
Set Myrng = .Rows(7).Find(What:="Difference", LookAt:=xlPart, SearchOrder:=xlByColumns, MatchCase:=False) '<--| find "Difference" in its 7th row
If Not Myrng Is Nothing Then GetRowQnt = WorksheetFunction.CountA(.Range(.Cells(8, Myrng.Column), .Cells(WorksheetFunction.Max(.Cells(.Rows.count, Myrng.Column).End(xlUp).row, 8), Myrng.Column))) '<--| count not blank cells in column where "Difference" was found from row 8 down to its last not empty cell
End With
End Function
and use it in your main code as follows:
With Windows("PassRate.xlsm").ActiveSheet '<--| reference "PassRate.xlsm" workbook active sheet (or change 'ActiveSheet' with 'Worksheetes("yourSheetName")')
For i = 1 To xlWorkbook.Worksheets.count '<--| loop through 'xlWorkbook' workbook worksheets
b = .Cells(.Rows.count, 3).End(xlUp).row + 1 '<--| get "PassRate.xlsm" workbook active sheet current first empty cell in column "C"
.Cells(b, 3) = xlWorkbook.Worksheets(i).Name
.Cells(b, 4) = GetRowQnt(xlWorkbook.Worksheets(i))
Next
End With
please note that with
b = .Cells(.Rows.count, 3).End(xlUp).row + 1
I took column "C" as the leading one to get last not empty row from, since there was no code in your post that wrote something in column "B".
But if your real code has some
.Cells(b, 2) = somedata '<--| write something in column "B" current row
then you can go back to b = .Cells(.Rows.count, 2).End(xlUp).row + 1

Return Column Header of Colored Cells

This process is being used for QC purposes. I have a spreadsheet that highlights certain cells that are wrong based off of their values and the validation rules we have in place. I was wonder if there was a way to return the column names of each cell that is colored into column A for each row? So for example if D2, F2, and G2 are wrong it would put all of those column headers in A2 to specify what exactly is wrong. I know it gets a bit more complicated trying to automate stuff with cell colors and I am not experienced in VBA which I'm assuming this will need. Is this possible to do, if so what would be the proper route to take? The data runs from column A to column BS, and the row numbers may differ, so if it could run up to row 1,000 that would be great. Attached is what the data looks like that I am working with.
The red means something is wrong in that row, and the orange cell is the color indicating that it is a wrong value
Yes, it is possible to do. Here is some snippets of code I pulled together to help get you started.
Lastrow = Cells(Rows.count, "A").End(xlUp).Row 'Get last row
With ActiveSheet
Lastcol = .Cells(1, .Columns.count).End(xlToLeft).Column 'Get last col
End With
For x = 1 To Lastcol 'Iterate Col
For i = 1 To Lastrow 'Iterate Row
'if red....
If Cells(i, x).Selection.Interior.Color = 255 then
'Move name to Cell A and append off of old name(s).
Cells(i, "A") = Cells(i, "A") & ", " & Cells(i, x)
End If
Next i 'next row
Next x 'next col