Find and select all cell ranges that are not empty - excel

I have a large range of cells that I am trying to select easily because it is too large to manually select and copy every time. I am looking for a way to quickly locate the entire range of data and select it. Not to be confused with only selecting every non-empty cell. There are cells within the big range that could be empty, but I also want to include them.
Example is my photo. I want to discover and select all the data that is A1:E7, including the cells in the middle that may be empty. If possible, I would want to de-select the heading as well and only select A2:E7.
So far I have managed to select everything with:
Range("A1").CurrentRegion.Select
But I am unsure how to de-select the top row after that.

Try this
Sub selectWithoutHeaders()
With Range("A1").CurrentRegion
.Offset(1, 0).Resize(.Rows.Count - 1).Select
End With
End Sub

You can use the handy UsedRange to determine the filled area on the sheet without checking each row and column for their last cell coordinates.
With UsedRange, you create a range stretching from A2 to the last cell, and then select it.
Sub Example()
Dim WS As Worksheet
Set WS = ActiveSheet
Dim LastCell As Range
With WS.UsedRange
Set LastCell = .Cells(.Rows.Count, .Columns.Count)
End With
WS.Range("A2", LastCell).Select
End Sub

Here is the Range(Cells(2, 1), Cells(LastRow, LastColumn)).Select version.
Public Function GetLastRowOfSheet(ws As Worksheet) As Long
Dim usedRng As Range
Dim lastRow As Range
Set usedRng = ws.UsedRange
Set lastRow = usedRng.Rows(usedRng.Rows.Count).EntireRow
GetLastRowOfSheet = lastRow.row
End Function
Public Function GetLastColOfSheet(ws As Worksheet) As Long
Dim usedRng As Range
Dim lastRow As Range
Set usedRng = ws.UsedRange
Set lastCol = usedRng.Columns(usedRng.Columns.Count).EntireColumn
GetLastColOfSheet = lastCol.Column
End Function
Sub SelectAllCells()
Dim ws As Worksheet
Set ws = ActiveSheet
Dim lastRow As Long: lastRow = GetLastRowOfSheet(ws)
Dim lastCol As Long: lastCol = GetLastColOfSheet(ws)
Range(Cells(2, 1), Cells(lastRow, lastCol)).Select
End Sub

Related

Delete Excel individual format condition

I have an old workbook with Conditional Formatting that has got out of hand in terms of random conditional formatting having evolved. I would like to loop through the sheet and delete all the conditional formatting that only refers to one cell (but preserve other formatting in the same cell and of course preserve the cell value etc.)
I have written the code in a separate sheet so that (1) I can re-use it and (2) the workbook itself doesn't need macros
So far, I can identify the cells but can't delete the formatting. The code I have is:
Option Explicit
Sub Delete_Conditional()
Dim fc As FormatCondition
Dim lLastRow As Long, lLastCol As Long
Dim rAllCells As Range, rCell As Range
Dim ws As Worksheet
Dim wb As Workbook
Set wb = Workbooks("Book1.xlsx")
Set ws = wb.Worksheets("Sheet1")
'Find last cell and set a range to cover all cells
lLastCol = ws.Cells(1, Columns.Count).End(xlToLeft).Column
lLastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
Set rAllCells = Range(Cells(1, 1), Cells(lLastRow, lLastCol))
'Loop through all cells
For Each rCell In rAllCells.Cells
'Loop through all FormatConditions in the cell
For Each fc In rCell.FormatConditions
'Determine if the FormatCondition only applies to one cell
If fc.AppliesTo.Cells.Count = 1 Then
Debug.Print fc.AppliesTo.Address
'I have tried fc.Delete
'I have tried fc.AppliesTo.Delete
End If
Next fc
Next rCell
End Sub
When I go back to the sheet, I can see the formatting still exists.
When deleting from a collection of items sometimes it works better if you work backwards:
Sub Delete_Conditional()
Dim fc As FormatCondition
Dim lLastRow As Long, lLastCol As Long
Dim rAllCells As Range, rCell As Range
Dim ws As Worksheet
Dim wb As Workbook, i As Long
Set wb = Workbooks("Book1.xlsx")
Set ws = wb.Worksheets("Sheet1")
'Find last cell and set a range to cover all cells
lLastCol = ws.Cells(1, Columns.Count).End(xlToLeft).Column
lLastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
Set rAllCells = Range(Cells(1, 1), Cells(lLastRow, lLastCol))
'Loop through all cells
For Each rCell In rAllCells.Cells
'Loop through all FormatConditions in the cell
For i = rCell.FormatConditions.Count To 1 Step -1
With rCell.FormatConditions(i)
If .AppliesTo.Cells.Count = 1 Then
Debug.Print .AppliesTo.Address
.Delete
End If
End With
Next i
Next rCell
End Sub

Copy Paste works only if Range is greater then 20 rows

Would you know what is the following code adjustment needed. Range I have set up (A1:B20) changes over time. The first block of data stays be between A1:B20 and the second block of data always will be between A25:B60. Ranges will change over time. First block of data could reach 200 rows going down. After my code reaches the second block of data and my range falls between that block of data it picks up the range only if I have adjusted manually the range. Please note, Second block of data normally provides duplicates from the first block.
How could I have my code automatically select the first block of data past my range output without having to adjust the "range" manually?
Sub CopyPaste()
Dim lastRow As Long
Dim Sheet2 As Worksheet
Dim Results As Worksheet
Dim LookupLastrow As Long
'code line will set values from sheet
("Sheet1") into ("Sheet2") starting 5 rows down.
Set Results = Sheets("Sheet2")
lastRow = ThisWorkbook.Sheets("Sheet2").Cells(Rows.Count, 1).End (xlUp).row
Range("A1:B20" & lastRowcount).Copy
Results.Range("A" & lastRow + 5).PasteSpecial xlPasteValuesAndNumberFormats
Application.GoTo ActiveSheet.Range("A1"), True
Application.CutCopyMode = False
End Sub
Think simple. No need to build strings for range addresses, and no need for using the clipboard with .Copy and .Paste. Use a direct assignment to the .Value property in a table of cells.
Public Sub CopyValues()
Dim r_src As Range, r_dst As Range
' Source starts at row 20
Set r_src = Sheets("Sheet 2").Cells(20, 1)
' Destination starts at row 5
Set r_dst = Sheets("Sheet 1").Cells(5, 1)
Dim n As Long
' Count the non-empty cells
n = r_src.Range(r_src, r_src.End(xlDown)).Rows.Count
' Copy n rows and 2 columns with one command
r_dst.Resize(n, 2).Value = r_src.Resize(n, 2).Value
End Sub
Based on the picture you showed, the following code will capture the entire top and bottom sections, regardless of how many lines or columns exists. This assumes your top section will start in "A8" as shown. You can edit the code to reflect your actual sheet names.
Sub CopyPaste()
Dim OrigLastRow As Long
Dim OrigLastCol As Long
Dim DestLastRow As Long
Dim OrigRng As Range
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Origin")
Set ws2 = ThisWorkbook.Worksheets("Destination")
OrigLastRow = ws1.Cells(Rows.Count, 1).End(xlUp).Row
OrigLastCol = ws1.Cells(10, Columns.Count).End(xlToLeft).Column
DestLastRow = ws2.Cells(Rows.Count, 1).End(xlUp).Row + 5
Set OrigRng = ws1.Range(ws1.Cells(8, 1), ws1.Cells(OrigLastRow, OrigLastCol))
OrigRng.Copy
ws2.Cells(DestLastRow, 1).PasteSpecial xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End Sub
The version below creates a top and bottom section like your picture and copies both sections separately with a 5 row gap in the destination.
Sub CopyPaste2()
Dim OrigLastRow As Long
Dim OrigLastCol As Long
Dim TopLastRow As Long
Dim BotLastRow As Long
Dim DestLastRow As Long
Dim OrigTopRng As Range
Dim OrigBotRng As Range
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = ThisWorkbook.Worksheets("Origin")
Set ws2 = ThisWorkbook.Worksheets("Destination")
'Assumes contiguous data from row 8 down
TopLastRow = ws1.Cells(8, 1).End(xlDown).Row
BotLastRow = ws1.Cells(Rows.Count, 1).End(xlUp).Row
OrigLastCol = ws1.Cells(10, Columns.Count).End(xlToLeft).Column
DestLastRow = ws2.Cells(Rows.Count, 1).End(xlUp).Row + 5
'Assumes we are starting the top range in row 8
Set OrigTopRng = ws1.Range(ws1.Cells(8, 1), ws1.Cells(TopLastRow, OrigLastCol))
'Columns I & J as shown in the picture
Set OrigBotRng = ws1.Range(ws1.Cells(TopLastRow + 5, 9), ws1.Cells(BotLastRow, 10))
OrigTopRng.Copy
ws2.Cells(DestLastRow, 1).PasteSpecial xlPasteValuesAndNumberFormats
'Recalculate destination last row
DestLastRow = ws2.Cells(Rows.Count, 1).End(xlUp).Row + 5
OrigBotRng.Copy
ws2.Cells(DestLastRow, 1).PasteSpecial xlPasteValuesAndNumberFormats
Application.CutCopyMode = False
End Sub

set a dynamic range from visible cells

I have some code in which I am trying to sort the data set in a csv file based on the content of a cell in another (the main) workbook. Then based on this sort, copy a range of visible cells between the first and sixth columns, but with a dynamic last row thus the range will be dynamic. This dynamic range is then pasted into the main sheet, which will then allow me to do further work on this dataset.
Can't seem to get the sort to work or the dynamic range working. I've tried all sorts of variation on the code below and am looking for some inspiration.
Sub Get_OA_Data()
'Find OA data from source SQL file and copy into serial number generator
Dim ws As Worksheet
Dim wkb2 As Workbook
Dim ws2 As Worksheet
Dim rng As Range
Dim rng2 As Range
Dim LastRow As Long
Dim LastColumn As Long
Dim StartCell As Range
'This section sets the workbooks and worksheets to be used for this macro
Set ws = ThisWorkbook.Worksheets("Data Entry")
Set wkb2 = Workbooks.Open("\\srvabdotfpr08\PC_APPS\forum\Gateshead Serialisation\sys_serialisation1.csv")
Set ws2 = wkb2.Worksheets("sys_serialisation1")
Set rng2 = ws.Range("F6")
' This line deletes any content of the cannot assign serial number added previously
ws.Range("I6:I7").ClearContents
'This hides all rows which do not match the desired OA number (found in rng2)
For Each Cell In ws2.Range("A1").End(xlDown)
If Left(Cell.Value, 6) <> rng2.Value Then
Cell.EntireRow.Hidden = True
End If
Next Cell
Set StartCell = ws2.Range("A1")
LastRow = StartCell.SpecialCells(xlCellTypeVisible).Row
LastColumn = StartCell.SpecialCells(xlCellTypeVisible).Column
'This section selects and copies the visible range from csv file into serialisation generator
Set rng = ws2.Range(StartCell.ws2.Cells(LastRow, LastColumn))
rng.Copy
ws.Activate
ws.Range("D12").Select
Selection.PasteSpecial 'Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
Any help would be greatly appreciated, I've bought a couple of books, but none of the stuff in my books is helping with this issue.
P.S I have used very similar code with specific set ranges and it works fine, but this one has me stumped. There may also be an issue with the dataset- which is why I have the LEFT formula in the code (but this seems to work OK).
Try...
Option Explicit
Sub Get_OA_Data()
Dim wkb2 As Workbook
Dim ws As Worksheet, ws2 As Worksheet
Dim rng As Range, xCell As Range
Dim LR As Long, LC As Long, LR2 As Long
Set ws = ThisWorkbook.Worksheets("Data Entry")
Set wkb2 = Workbooks.Open("\\srvabdotfpr08\PC_APPS\forum\Gateshead Serialisation\sys_serialisation1.csv")
Set ws2 = wkb2.Worksheets("sys_serialisation1")
ws.Range("I6:I7").ClearContents
LR2 = ws2.Range("A" & ws.Rows.Count).End(xlUp).Row
For Each xCell In ws2.Range("A1:A" & LR2)
xCell.EntireRow.Hidden = Left(xCell.Value, 6) <> ws.Range("F6")
Next xCell
LR = ws2.Range("A" & ws.Rows.Count).End(xlUp).Row
LC = ws2.Cells(1, ws.Columns.Count).End(xlToLeft).Column
Set rng = ws2.Range(ws2.Cells(1, 1), ws2.Cells(LR, LC))
rng.SpecialCells(xlCellTypeVisible).Copy
ws2.Range("D12").PasteSpecial xlPasteValues
End Sub

Variable range in Visual Basic for Excel

I want to define a variable range in an Excel macro with VBA. The first cell is always A25, but the last cell is moving depending on the number of data collected. This can be E35, or E58, etc. Any idea how to do this?
There are 2 options:
Option 1: the Range you are looking to define is continuous (see screen-shot below):
the easy approach will do:
Option Explicit
Sub DefRange()
Dim Rng As Range
With Worksheets("Sheet1") '<-- modify "Sheet" to your sheet's name
Set Rng = .Range("A25").CurrentRegion
Debug.Print Rng.Address '<-- for debug: will show A25:E35
End With
End Sub
Option 2: the Range you are looking to define, has an empty line in the middle (screen-shot below):
then, the previous method will result with the wrong range
Option Explicit
Sub DefRange()
Dim Rng As Range
Dim LastRow As Long
Dim LastCol As Long
With Worksheets("Sheet1") '<-- modify "Sheet" to your sheet's name
Set Rng = .Range("A25").CurrentRegion
Debug.Print Rng.Address '<-- for debug: will show A25:E35 ***WRONG***
'Search for any entry, by searching backwards by Rows.
LastRow = .Cells.Find(What:="*", After:=.Range("A25"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'Search for any entry, by searching backwards by Columns.
LastCol = .Cells.Find(What:="*", After:=.Range("A25"), SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
Set Rng = .Range(.Cells(25, "A"), .Cells(LastRow, LastCol))
Debug.Print Rng.Address '<-- for debug: will show A25:F37 ***CORRECT***
End With
End Sub
You can define a range as its two limit cells. Let's say you are working in the worksheet "ws":
Dim rng As Range
Dim cl1 As Range: Set cl1 = ws.Range("A25")
Dim cl2 As Range
Set cl2 = ws.Range("E35") 'Or something else'
Set rng = ws.Range(cl1, cl2)
Just count the rows in Column E,
Sub Button1_Click()
Dim LstRw As Long
Dim Rng As Range, x
LstRw = Cells(Rows.Count, "E").End(xlUp).Row
x = IIf(LstRw > 25, LstRw, 25)
Set Rng = Range("A25:E" & x)
Rng.Select
End Sub

Make the Code adapt to the changes instead of hardcode as shown in below

what am i going to do if there are new data added into the excel, instead of changing my code( hard code), for let say if i add data in row 6, row 7, then i have to declare rng6 for range(A6:LY6).As i am still new in excel vba, need some examples for this case. Thank you very much. Hope the editing makes the question understandable. Sorry once again for din specify it clearly.
Dim rng1 As Range
Dim rng2 As Range
Dim rng3 As Range
Dim rng4 As Range
Dim rng5 As Range
Set rng1 = Range("A1:AC1").SpecialCells(xlCellTypeBlanks)
Set rng2 = Range("A2:LY2").SpecialCells(xlCellTypeBlanks)
Set rng3 = Range("A3:LY3").SpecialCells(xlCellTypeBlanks)
Set rng4 = Range("A4:LY4").SpecialCells(xlCellTypeBlanks)
Set rng5 = Range("A5:LY5").SpecialCells(xlCellTypeBlanks)
rng1.Rows.Delete Shift:=xlToLeft
rng2.Rows.Delete Shift:=xlToLeft
rng3.Rows.Delete Shift:=xlToLeft
rng4.Rows.Delete Shift:=xlToLeft
rng5.Rows.Delete Shift:=xlToLeft
As I understand it, you want to delete blank cells from each row, but you dont know how many rows you have?
The first step is to determine how many rows you need to edit?
If column A always contains info (non-blank), you can simply write lastRow = Range("A1").End(xlDown).Row to get the last non-empty cell in column A
If column A contains blanks, you'll have to figure out a clever way to get the range you want to edit, ActiveSheet.UsedRangefor example.
Now loop through the rows and edit them.
Sub test()
Dim rng As Range
Dim row As Integer
Dim lastRow As Integer
'To avoid errors when no empty cells are found:
On Error Resume Next
'Unless you have Another way to determine how many rows to delete:
lastRow = Range("A1").End(xlDown).Row
'Loop through the rows:
For row=1 To lastRow
'Select the empty cells in this row:
Set rng = Range("A" & Row & ":LY" & Row).SpecialCells(xlCellTypeBlanks)
'Delete the empty cells:
rng.Delete Shift:=xlToLeft
Next
End Sub
Hope this is what you're looking for.
Code for dynamic selecting all range data (finding last row and column), assuming your data has the same number of columns to all rows.
Dim lastCol As Long
Dim lastRow As Long
Dim rng1 As Range
With ActiveSheet
lastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set rng1 = Range(Cells(1, 1), Cells(lastRow, lastCol)).SpecialCells(xlCellTypeBlanks)
End With

Resources