Select discontinuous range based on column A - excel

I have data in columns A:I. The data in column A will always go through to the last row, but other rows in other columns will sometimes be blank. How do I select the range based on the last row in column A? For example, sometimes column A will have 40 rows of data but column I will be blank after row 3. I would still want to select A1:I40.
Ultimately, I want to use VBA to format and put a filter on this range, so I am hoping to not include any blank rows after the last used row in column A.

Consider:
Sub qwerty()
Dim N As Long
N = Cells(Rows.Count, "A").End(xlUp).Row
Range("A1:I" & N).Select
End Sub

Gary's Student gave you the answer
maybe you're interested in expanding the feature and want to consider the last row with at least one non blank cell in the whole columns range (columns "A:I" in your example), irrespective of which column has it, than you could use:
Function LastRow(sht As Worksheet, columnsStrng As String) As Long
With sht
With Intersect(.UsedRange, .columns(columnsStrng)).SpecialCells(xlCellTypeConstants)
LastRow = .Areas(.Areas.Count).Row
End With
End With
End Function
and here follows an example of how to use it
Option Explicit
Sub main()
Dim ws As Worksheet
Set ws = Worksheets("mysheet1")
ws.columns("A:I").Resize(LastRow(ws, "A:I")).Select
End Sub
This assumes your data are constants (i.e. actual cells content is not a "formula").
But it can be easily enhanced to consider "formula" data as well

Related

Extract the first column number from an address in VBA

I want to extract the number from the first column of a defined range in VBA. Currently, my code looks like this:
Sub Column_Number()
Sheet1.Range("A1").Value = Sheet1.Range("$C$6:$I$6").Address
End Sub
The expected result in Cell A1 should be 3 because Column C is the first column in the Range("$C$6:$I$6") and the third column in the entire sheet.
I tried to go with the solution from here but could not make it work.
Instead of the column number it returned the value in Cell $C$6.
How do I need to modify my VBA to get the expected result?
Use Column property of Range object. Try below.
Sub Column_Number()
Sheet1.Range("A1").Value = Sheet1.Range("$C$6:$I$6").Column
End Sub
In this way, you will have the column number and its letter, too:
Dim sh As Worksheet, rng As Range
Set sh = Sheet1
Set rng = sh.Range("$C$6:$I$6")
Debug.Print rng.column, Split(rng.Address, "$")(1)

How to make Formula give multiple results across other cells

So I'm working on an excel sheet, and this is something i really can't figure out.
I want it to be that if the contents of a cell match certain criteria, an entire column of cells will be pasted according to that cell. The cell is a drop down with 32 different options (that can be reduced if theres no way to do it) and each option corresponds to a different column of data. The columns that have to be pasted have roughly 32 cells of data each.
My current formula is basically =IFS(A1="Potato",Sheet2!G:G) but this gives me a '0'. The best i can do is change the formula to =IFS(A1="Potato",Sheet2!G1) or =IFS(A1="Potato",Sheet2!G1:G32) but both of these formulas give me the contents of the first cell only (G1).
Any ideas on how I could get this done without having to contact aliens or build a spaceship?
You can use formulas, or VBA.
I have assumed your 32 columns of source data are in Sheet2 with the headers in row 1.
Formula Solution
In Sheet1 A73, enter:
=INDEX(Sheet2!$A$1:$AF$41,ROW(A1),MATCH($A$1,Sheet2!$A$1:$AF$1,0))
Copy this formula to Sheet1 A74:A105
VBA Solution
Put this code in the Sheet1 module;
Private Sub Worksheet_Change(ByVal Target As Range)
Dim c As Range
If Not Intersect(Target, Range("A1")) Is Nothing Then
Application.EnableEvents = False
With Sheet2
Set c = .Rows(1).Find(what:=Sheet1.Range("A1").Value)
If Not c Is Nothing Then
Set c = Intersect(.UsedRange, c.EntireColumn)
Sheet1.Range("A73").Resize(c.Rows.Count, 1).Delete
c.Copy Sheet1.Range("A73")
End If
End With
Application.EnableEvents = True
End If
End Sub
EDITED ANSWER: (according to comment)
We have the following layout of products
Private Sub CommandButton1_Click()
'first we check the user input
Dim u_input As String
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
u_input = LCase(Trim(ws.Range("A1").Value2))
'now we need to determine how many columns there are so we know when to stop looping
Dim lc As Long, lr As Long
lc = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
' loops through all the products
For Each cell In Range(Cells(1, "F"), Cells(1, lc))
' if the product matches the input
If LCase(Trim(cell)) = u_input Then
lr = ws.Cells(ws.Rows.Count, cell.Column).End(xlUp).Row
' copy and paste the active data range to A37
ws.Range(Cells(1, cell.Column), Cells(lr, cell.Column)).Copy
Sheets("Sheet2").Range("A37").PasteSpecial
End If
Next cell
End Sub
So, upon entering cucumber and clicking the button:
We would get the following result:
You can add any number of products there, as long as the first product starts in column F. (though that can also be changed in code).
PS: This will however end up overwriting your data and also cause data to overlap if your data ranges are not the same. It probably would be smarter to paste the data into the next empty row in sheet2 instead of directly to A37
This can be achieved by changing the line
Sheets("Sheet2").Range("A37").PasteSpecial to Sheets("Sheet2").Range(Cells((Rows.Count, "A").End(xlUp).Row, "A")).PasteSpecial

How to use Rows(x:x) .select in IF statement

I have a spreadsheet where I have a macro built to whittle down the amount of data to something manageable. The next step is to compare the value of a column cell to a predefined number determined in the macro and placed in another cell away from the data. If the value is less than the predetermined value, I want to delete the entire row, then go on to the next row and do it again. In the end, all I should have left is the rows where that column is greater than the predetermined value.
Let's say the column is C and the predetermined value is in M1. How would I do this?
BTW, the macro to date has filtered the data based on Column C from largest to smallest, so I'm basically looking to find the first value in C to be less than the other value, then highlight everything underneath and delete it.
Thanks for any help.
You didn't specify if you had a Header row or not, but for your exact request here you go.
Option Explicit
Sub DeleteRows()
Dim ws As Worksheet, myVal As Double
Dim Cell As Range, RngC As Range, CompRng As Range
Set ws = ThisWorkbook.Worksheets(1)
Set RngC = ws.Range("C:C")
Set CompRng = ws.Range("M1")
myVal = CDbl(CompRng.Value)
For Each Cell In RngC
If CDbl(Cell.Value) < myVal Then
Cell.EntireRow.Delete
End If
Next Cell
End Sub

Working with the Columns function - Excel VBA

I have been looking around the site for a while for an answer to this question but no luck just yet. I have this code where I loop through a row of numbers and depending on what number is in the cell at the time, determines what I copy and paste to the sheet. I am using Columns for this because it is the only way I can make my code dynamic. It works but when I paste I would like to paste in cells lower than where it's pasting right now. I was wondering if Columns had a way of specifying what column and where to paste my data.
Code:
Dim sh As Worksheet
Dim rw As Range
Dim row As Range
Dim cell As Range
Dim RowCount As Integer
Set rw = Range("A5:CG5")
Set sh = ActiveSheet
For Each row In rw.Rows
For Each cell In row.Cells
Select Case cell.Value
Case "2"
ThisWorkbook.Worksheets("Sheet1").Range("E27:E51").Copy Destination:=Sheets("Sheet2").Columns(4)
End Select
Next cell
Next row
Your problem can be solved as Jeeped said, use Destination:=Sheets("Sheet2").Cells(27, 5) or Destination:=Worksheets(2).Range("E27")
Since you want to learn a little bit more, i made an example explanation:
https://msdn.microsoft.com/en-us/vba/excel-vba/articles/range-column-property-excel
On the link it is explained that .Column:
Column A returns 1, column B returns 2, and so on.
And the same is with the .Rows
Use .Cells https://msdn.microsoft.com/pt-br/library/office/ff194567.aspx So you can use the .Cells(Rows,Columns) or .Cells(Index from a Range) or the entire Object:
With Worksheets("Sheet1").Cells.Font
.Name = "Arial"
.Size = 8
End With
So an example if you want to turn your spreadsheet dynamical: to copy from range $E$27 to last row with something written from column $E on Sheet1 To
the last column with nothing written on row 1 on Sheet2.
Sub test()
'Declare variables here
Dim sht1, sht2 As Worksheet
'sht1 has the data and sht2 is the output Worksheet, you can change the names
last_row = Worksheets(1).Range("E65536").End(xlUp).Row
last_column = Worksheets(2).Cells(1, sht1.Columns.Count).End(xlToLeft).Column
'Data add
For i = 27 To last_row
'Start from Row 27
Worksheets(2).Cells(i - 26, last_column + 1) = Worksheets(1).Cells(i, 5)
Next i
MsgBox "Data Updated"
End Sub
And an example of a basic dynamical workbook with i=i+1 and For loops split a single row of data into multiple unique rows into a new sheet to include headers as values and cell contents as values

Selecting data within a recorded macros

I am trying to record a macro to automate formatting usage reports. The reports don't all have the same number of rows or columns.
What I want to do is select all columns and rows with data. When recording if I click Ctrl+Shift+Down+Right it will select the data on that report. However, if I run it on a set of data with more rows or columns it won't include it in the selection.
Is there a way to select from a starting cell to the end of the rows or columns of available data?
Using relative reference will definitely get you the correct coding. Or you can just put this code Range("A1").CurrentRegion.Select into the appropriate place in the macro (where you put the top leftmost cell in the place of the "A1").
If you want to do more advanced work you can save the current region as a variable and use different properties on it to do things other than simply select the area.
For example:
sub test()
dim rng as range
dim rw as integer
dim col as integer
set rng = Range("A1").CurrentRegion 'choose the top leftmost cell in the range
rw = rng.rows.count 'counts the number of rows in the selection
col = rng.columns.count 'counts the number of columns
rng.select 'selects the range in an efficient manner
rng.columns(2).select 'selects the second column in the range
rng.rows(2).select 'selects the second row in the range
rng.cells(1,2).select 'selects the cell on the first row and second column in the range
end sub
Hopefully this is helpful. I just wanted to expand on some more things you could do to work with the ranges you have.

Resources