Read Value from a merged Range (Excel) - vba

I have a column whose header is a range of B1:C1. the data is more like
+----+----+
| Header |
+----+----+
| H2 | H3 |
+----+----+
| 1 | 2 |
| 3 | 4 |
+----+----+
I have a variable named rng such as
Set rng = Range("B1:C1")
now using rng variable, I want to select value "H3" or "2", or "4". I used the following syntax
rng.Offset(1,1).value
and isntead of giving me "H3" it gave me value from next colum i.e d2.

There is not a straight forward way to fix this unexpected behaviour. My understanding is that, regarding merged cells, the reference for the offset is based on the whole of the cell and that the merged cells are treated as one cell instead of many cells.
In your instance, if Range("B1:C1") is merged then the next column (i.e Offset(0,1)) is column D. Excel views the merged range as single cell and so from a visual standpoint the next column along is column D and not column C. This can be confusing in my view.
The best way to work around this is to avoid using merged cells as headers but instead use Centre Across Selection formatting:
1) De-merge Range("B1:C1")
2) Select Range("B1:C1") > Format > Cells
3) In Horizontal dialog box select 'Center Across Selection'
If you do that then the following code will work:
Sub GetOffsets()
Dim rng As Range
Set rng = Range("B1")
Debug.Print rng.Offset(1, 0) // H2
Debug.Print rng.Offset(2, 0) // 1
Debug.Print rng.Offset(3, 0) // 3
Debug.Print rng.Offset(1, 1) // H3
Debug.Print rng.Offset(2, 1) // 2
Debug.Print rng.Offset(3, 1) // 4
End Sub

If you really need to use merged cells, Excel has this "issue" when it comes to offsets from merged cells. In your case above, it does make sense that cell D2 becomes offset(1,1) from B1.
One solution is to use nested offsets:
You have your variable:
Set rng = Range("B1:C1")
Then use the following adjustment to your code:
rng.Offset(1,0).offset(0,1).value
This way, you first offset by row, to move down to B2, then offset by column to get to C2.

Related

finding sum of squares of column using for each

I am a newbie. I want to sum the squares of the numbers in the active column. I am getting an error 'object doesn't support this method'. Here is my code
Sub sum_squares()
Dim total As Integer
Dim c As Range
Dim d As Range
'set d equal to column from active cell down to last non-empty'
d = Range(ActiveCell, ActiveCell.endxldown)
total = 0
For Each c In d
total = total + c.Value ^ 2
Next c
End Sub
Appreciate the help.
Thanks
As has been pointed out you've got the syntax of xlDown incorrect.
You should also start at the bottom and move up - xlDown may not find the last cell.
E.g.
With a value in cell A1:A3 and A1 as the ActiveCell it will correctly return A3.
Same scenario but with A4 left blank and a value in A5 still returns A3.
Same scenario with A1 left blank it returns A2.
This will return a reference from the ActiveCell to the last cell containing a value in that column.
Note that if the ActiveCell is lower down than the last cell containing data you'll get a reference reflecting that.
Set d = Range(ActiveCell, Cells(Rows.Count, ActiveCell.Column).End(xlUp))
A Range can be made up of one or more cell references:
Range("A1") and Range("A1,A3,C5") reference individual cells.
Range("A1:C5") and Range("A1", "C5") reference all cells between the first and last address.
A Cell is a single cell reference that uses row and columns identifiers.
Cells("A1") will return an error as it's a full address.
Cells(1,"A") will return A1 (row 1, column A)
Cells(1,1) will also return A1 (row 1, column 1)
The code above is using two cell addresses to reference all cells between the two.
Range(ActiveCell,....) is the reference to the first cell.
Cells(Rows.Count, ActiveCell.Column) is the reference to the second cell using row numbers and column numbers.
If the ActiveCell is in column B then this is the same as writing Cells(1048573,2).
The End(xlUp) then goes from that cell back up to the first one containing data.
There is a syntax error in your code - .endxldown and add Set before assigning range.
Correct it to -
Set d = Range(ActiveCell, ActiveCell.End(xlDown)

VBA Delete row based on 2 columns

I have some VBA code that will delete the entire row if a cell in a column has red text
Dim Cell As Range
For Each Cell In Intersect(Columns("L"), ActiveSheet.UsedRange)
If Cell.DisplayFormat.Font.ColorIndex = 3 Then Cell.Value = "#N/A"
Next
On Error GoTo NoRedText
Columns("L").SpecialCells(xlConstants, xlErrors).EntireRow.Delete
NoRedText:
I would like to extend this code to also include another column that includes a "Y" value in the cell.
Column L includes the red text string
Column P includes the "Y" text string
Therefore if the text is red in column L AND the text is equal to "Y" in column P it should delete the entire row
What do I need to add to the code to achieve this?
Thank you
Your Cell variable references a range and all the properties that go with it.
The Offset property
Returns a Range object that represents a range that's offset from the
specified range.
(https://msdn.microsoft.com/en-us/library/office/ff840060.aspx)
Using this knowledge you can tell your code to look at the range that is offset by four columns:
If Cell.DisplayFormat.Font.ColorIndex = 3 AND Cell.Offset(,4)="Y" Then Cell.Value = "#N/A"

If Statement to check Excel column for a match value

I want to use an If statement (VBA code) to check the cell range in a column for a given numeric parameter. For the cell that matches the given value, the cells at the right (in the same row) should change the background color.
Pseudocode Example:
A1=5,7
If cell in Range(F1:F10) has value=A1 Then
(random matched cell: F7=5,7)
Range (G7:M7) = Background Blue
The part to change the background I know how to do it, but what is the best way to check the given range?
I think you want something like
for i = 1 to 10 'rows in column f to loop through
if cells(i,6) = cells(1,1) then 'column a is 1, column f is 6, etc.
range(cells(i,7), cells(i,13)).interior.colorindex = 'number for that color
end if
next i
I'm guessing you may have multiple rows in F1:F10 that have a match on A1. I would iterate through the cells in the range with:
For each rngCell in Range("F1:F10")
If rngCell.value = Range("A1").value
Range("G" & rngCell.row, "M" & rngCell.row).Interior.ColorIndex = 5
End If
Next

Weird behaivour getting value from merged cell

I've come across this behaivour in Excel. Given these cells:
A B C D
|---------|---------|---------|---------|
1 | merged cell text | foo | bar |
|---------|---------|---------|---------|
2 | | | | |
|---------|---------|---------|---------|
When Cell C1 is selected (foo), the following VBA statement returns an empty string:
Debug.Print Selection.Offset(0, -1).Range("A1").Value
This next VBA however returns the expected value (merged cell text):
Selection.Offset(0, -1).Select
Debug.Print Selection.Range("A1").Value
I can't for the life of my figure out why - surely as Offset returns a Range and Selection is also a Range, it's just breaking down the same behaivour over multiple lines, and getting different results. The behaivour does not occur when there are no merged cells.
Can anyone explain what's going on here?
This should be the reason:
Debug.Print Selection.Offset(0, -1).Range("A1").Value
Your current selection is C1, offset -1 column gives you B1. You are trying to print A1's value while selecting B1, thus gives nothing. Merged cell does not automatically cause both A1 and B1 being selected.
(you can test by printing B1's value instead). However:
Selection.Offset(0, -1).Select
Debug.Print Selection.Range("A1").Value
selects the range B1 first, which when merged, cause it to select both A1 and B1 on a application level, thus able to print A1's value
Hope that's clear to you
if you want to read the value in a1 from anywhere of the mergedcell,
Debug.Print Range("anyCellFormMergedRange").cells(1,1).Value 'wich gets the value from the first cell of a bigger range (here A1:B1)
or
Debug.Print Range("anyCellFormMergedRange").MergeArea(1, 1).value 'wich gets the value from the first cell of a MERGED range (here A1:B1)
'for a small mergedcell like yours, a simple .mergearea(1) works too
you can change the range to anything you need (selection, .offset(x,y), activecell ...) wich are also ranges.
if you want to use the whole mergedCells (A1:B1), without using .select :
(from C1)
Debug.Print selection.offset(0,-1).MergeArea.address
Also remember that comment, validation data, are also contained in the first cell of the range (A1 here).

Excel VBA conditional formatting based on next cell value

I am trying to do some conditional formatting in Excel for the font size but seeing as it can't be done from the format menu, it needs to be done with VBA.
I have a range B6 to however many rows and I want to look at the cell next to it and see if it's blank (column C). If it is then format the cell to Bold and 11pt. If it's not blank then it needs to be normal and 9pt.
My code at the minute only makes the last row Bold and 11pt and the rest of the column, even if column C is empty will be normal 9pt.
What is going wrong? BTW I'm using Excel 2003
Dim c As Range, rng
Dim LASTROW As Long
LASTROW = Cells(Rows.Count, 1).End(xlUp).Row
Set rng = Range("B6:B" & LASTROW)
For Each c In rng
If Len(c.Offset(1, 0)) = 0 Then
c.Font.Bold = True
c.Font.Size = 11
Else
c.Font.Bold = False
c.Font.Size = 9
End If
Next c
Your Offset parameters are backwards. You are checking the cell below the current one.
Note the trick is to use a single rule, coded for the top-left cell
This doesn't need a macro - you can do it using a formula in Conditional Formatting.
Say you wanted to highlight the adjacent cell in column B red when the cell in column C had a value of "Red":
=IF(C6="Red",TRUE,FALSE)
then just fill down with the fill handle as usual.
Rule editor (2007):