Creating a dynamic range between two named cells with set number of columns - vba

I need to create a dynamic range between two named cells (the cells and corresponding rows shouldn't be included in the selection). The number of columns is always the same (4), only the number of rows is changing. That's the first step.
Second one is putting several these ranges into a numbered list in another excel list, but that is something I can hopefully figure out myself. Thank you very much.

I might try something like this:
Sub RangeBetween()
Dim rng1 As Range, rng2 As Range
Dim betRange As Range
Set rng1 = Range("A1") 'sample data
Set rng2 = Range("A20")
Set betRange = Range(rng1.Offset(1, 0).Address & ":" & rng2.Offset(-1, 3).Address)
End Sub
This is of course assuming that your named cells are along the same column. If your named cells always spread 4 columns by default, replace the Offset(-1, 3) with Offset(-1, 0).

This code defines a named range with the name "NewNamedRange". The code assumes (and requires) that your bracketing cells are already named ranges, with the names "UpperLeft" and "LowerRight". The offset formulas exclude the bracketing cells from the named range. So if "UpperLeft" is cell D2, and "LowerRight" is cell G22, "NewNamedRange" will be the range "D3:G21". Because the named range definition is a formula, NewNamedRange will change dynamically as the bracketing cell definitions change. Hope this helps.
Sub NamedRange()
ActiveWorkbook.Names.Add _
Name:="NewNamedRange", _
RefersTo:="=OFFSET(UpperLeft,1,0):OFFSET(LowerRight,-1,0)"
End Sub

Related

Adding a single cell to a Range in a formula

I have a Sub that dynamically selects a range of cells and then passes that range in to the Internal Rate of Return Formula. I need to have a single cell appended to the beginning of the range for the formula to work. See below:
Dim calcrange As Range
Set calcrange = Range(Range("B57"), Range("B57").End(xlToRight))
Range("IRR").Formula = "=IRR(" & calcrange.Address & ")"
So ideally, what I'd like to do is add a named range cell "InvestmentOutlay" to be the first cell in the range. The InvestmentOutlay Cell is on a previous sheet, but the order I'd like the formula to run through is
=IRR(InvestmentOutlay,B57,C57, etc)
... Is this possible to do?
Like this, using Union to join two ranges?
Set calcrange = Union(Range("InvestmentOutlay"), Range(Range("B57"), Range("B57").End(xlToRight)))

Faster Workflow

I have a table (Table 1) with a whole bunch of well data (versions, MD, HD, etc.) and I want to create another table (Table 2) that will only show the data for the well I am interested in.
I have it set up where you select the well using a drop down list. Then I want Table 2 to be populated with four values for each of the iterations that show up in Table 1....
I tried using vlookup but was having issues when a well had multiple versions. And I also tried using an advanced filter.
Screenshot of the spreadsheet
Let's solve this using a helper column. First, assume column A will be used to the left of your table, to show the row number which each one of these is found in.
A5 would have the following formula:
=MATCH($C$1,K:K,0)
This shows us the row number that Well1 is first matched at. Then A6 and copied down would have the formula:
=A5+MATCH(B6,OFFSET(K1,A5,0,COUNT(M:M),1),0)
This uses OFFSET to create a new range, starting at the cell immediately below the previous match for Well1, and then uses MATCH to find what row that occurs.
So now, column A will always show the row number to pull data from. The rest is simply using the INDEX function to pull from your desired columns. For example, the data in column C pulls the iteration from column L, and can be pulled through formula like so, in cell C5 and copied to the right / down:
=INDEX(L:L,$A5)
If your data is appropriately normalized, you might be better off with a Pivot Table. This would give you the option of filtering by Well ID.
To use a Advanced filter you will need to create a worksheet event. Place this in the code for the sheet on which you want the data.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A2")) Is Nothing Then
Dim dataRng As Range
Dim critRng As Range
Dim CpyToRng As Range
Dim cpytoarr() As Variant
With Worksheets("Sheet1")
Set dataRng = .Range(.Cells(1, 1), .Cells(1, 1).End(xlDown).End(xlToRight))
End With
With Me
.Range("CC1") = .Cells(1, 1).Value
.Range("CC2") = "'=" & .Cells(2, 1).Value
Set critRng = .Range("CC1:CC2")
Set CpyToRng = .Range(.Cells(6, 1), .Cells(6, 1).End(xlToRight))
End With
Debug.Print dataRng.Address
Debug.Print critRng.Address
Debug.Print CpyToRng.Address
dataRng.AdvancedFilter Action:=xlFilterCopy, _
CriteriaRange:=critRng, CopyToRange:=CpyToRng, _
Unique:=False
critRng.ClearContents
End If
End Sub
How this works. This assumes the data is on Sheet1 and starts in "A1" with no blanks in column A or the last row:
On Sheet2 set it up like this:
It is important that the header rows on sheet2 are name identical to the headers on sheet1.
Now every time that the value changes in A2 on sheet 2, your drop down, the requisite data will appear below row 6.

First value twice when using unique filtering (VBA)

I have made a very simple Visual Basic script, which uses the advanced filter function in Excel, to copy unique values from a column in one sheet, to a column in a different sheet. It works fine on all values, except the first which appears twice. Can anyone tell me the reason for this glitch? I tried using the filter manually, with the same result.
Sub getUniqueRuns()
Sheets(2).Range("C2:C65536").AdvancedFilter Action:=xlFilterCopy,
CopyToRange:=Sheets(5).Range("A2"), Unique:=True
End Sub
The AdvancedFilter is using the top row of your range as the title and then providing distict values from the rest of the range. As you have provided row 2 as the first row, it is using this as the header and then rows 3 onwards as the data. As a result you are getting duplicates. I suggest you change your ranges to the below which will then copy the heading across.
Sub getUniqueRuns()
Sheets(2).Cells.Clear
Sheets(2).Range("C1:C65536").AdvancedFilter Action:=xlFilterCopy,
CopyToRange:=Sheets(5).Range("A1"), Unique:=True
End Sub
I had the same issue with a script of mine, I resolved it with a .offset(1) to offset the extra row in rgData.
Sub modHouse_Popularity()
'
' modHouse_Popularity Macro
' Select Houses and remove duplicates
'define range
Dim rg As Range
Set rg = ThisWorkbook.Worksheets("Popularity").Range("A2:A500")
'retain header
rg.Offset(1).ClearContents
'define data fields, criteria fields and out put fields
Dim rgData As Range, rgCriteria As Range, rgOutput As Range
Set rgData = ThisWorkbook.Worksheets("Facade requests").Range("Table1[House]").Offset(1)
Set rgCriteria = ThisWorkbook.Worksheets("Popularity").Range("a2")
Set rgOutput = ThisWorkbook.Worksheets("Popularity").Range("a3:a500")
'place data
rgData.AdvancedFilter xlFilterCopy, rgCriteria, rgOutput, True

Trying to create a range from a set of values

So I have a range of cells that contains a list of Cell Addresses.
Column B & C show where a block of information starts and ends. Column D states whether it is the start of a combination of tables, the end of the combination, or whether it's a single Table.
So basically I am having some difficulty combining the answers from B & C to form a combined range. So in the picture, Column E shows the start as A170 and the End as A596. (I don't think this is necessary tbh) I need to make a range containing A170:A543, A548:A554, etc. and it needs to be dynamic. So these should create themselves based on the values in Column D. I'm looking to do this in VBA, but if it's easier to do in Excel Formulas, that's okay too.
Can anyone give me some hints how to accomplish this? My brain is currently mush.
You can create a small User Defined Function (aka UDF) that will stitch together the non-contiguous cell ranges from textual representations of their respective addresses. This can return a range for a native worksheet function that uses a cell range like the SUM function or COUNTA function (to use two very simple examples).
Function makeNoncontiguousRange(startRNGs As Range)
Dim rng As Range, rUNION As Range
For Each rng In startRNGs
If rUNION Is Nothing Then
Set rUNION = Range(rng.Value2, rng.Offset(0, 1).Value2)
Else
Set rUNION = Union(rUNION, Range(rng.Value2, rng.Offset(0, 1).Value2))
End If
Next rng
'Debug.Print rUNION.Address
Set makeNoncontiguousRange = rUNION
End Function
The function could be used on a worksheet like,
=SUM(makeNoncontiguousRange(B2:B4))
In your data sample this would be like writing,
=SUM($A$170:$A$543,$A$548:$A$554,$A$558:$A$566)
Note that I am only passing in the start of the range in column B and gaining the end range with .Offset. If you need to expand the functionality to pass in the end range then you will need to check if both the start and end ranges are the same size.

Copy/Paste cells next to cells that have certain string

I am trying to look up cells in a certain column that have a string (e.g. Names), copy the corresponding cells in the column to its right (i.e. offset(0,1) ), then paste it to a column in a different sheet. I have the following code to find the range variable that I want. However, I can't select it from a different sheet!
When I use Sheets(1).MyRange.Copy, it doesn't accept it. Am I referring to the range in a wrong way? What am I doing wrong?
Here's code that I use to get MyRange:
Option Explicit
Sub SelectByValue(Rng1 As Range, Value As Double)
Dim MyRange As Range
Dim Cell As Object
'Check every cell in the range for matching criteria.
For Each Cell In Rng1
If Cell.Value = Value Then
If MyRange Is Nothing Then
Set MyRange = Range(Cell.Address)
Else
Set MyRange = Union(MyRange, Range(Cell.Address))
End If
End If
Next
End Sub
Sub CallSelectByValue()
'Call the macro and pass all the required variables to it.
'In the line below, change the Range, Minimum Value, and Maximum Value as needed
Call SelectByValue(Sheets(1).Range("A1:A20"), "Tom")
End Sub
One More Question: Rather than specifying the exact range to look at (e.g. "A1:A20"), I would LOVE to look at all of column A. But I don't want to use ("A:A") so it wouldn't look at all rows of A. Isn't there a method to look only in cells that have entries in column A?
Thank you VERY much.
Al
You only need MyRange.Copy.
To restrict only to cells in column A which might have values, you could use
With Sheet1
Set rngToSearch = Application.Intersect(.Columns(1), .UsedRange)
End With
...or maybe look at .SpecialsCells()