I am trying to find out how to fill a cell on the next empty row, using a loop.
I learned how to loop through a range, and how to fill cells conditionally, for example:
Dim column As Range: Set column = Sheets(1).UsedRange.Columns(1)
For Each cell In column.Cells
If cell.Value >= 0 Then
cell.Offset(0, 1).Value = "Positive"
ElseIf cell.Value < 0 Then
cell.Offset(0, 1).Value = "Negative"
End If
Next
However, my current task is a bit more complex, and I do not know how to solve a particular issue. I have two sheets, one in each workbook. If, when looping through a column in the first workbook, I find an empty cell, then the value in the cell that is 0,1 offset to it should be copied to a column in the second workbook.
My objective is thus that the second workbook contains a tidy column, with one value after the other row by row. The first workbook remains unchanged.
The particular issue is that I can't find what the exact syntax or condition to tell Excel to fill a cell on the first empty row that it finds.
This is what I have so far:
Dim wb As Workbook: Set wb = Workbooks("QuartalReport.xlsm")
Dim ws As Worksheet: Set ws = wb.Worksheets(1)
Dim column As Range: Set column = ws.Sheets(1).UsedRange.Columns(1) 'some cells in this column are empty
Dim wb2 As Workbook: Set wb2 = Workbooks("ClientList.xlsm")
Dim ws2 As Worksheet: Set ws2 = wb2.Worksheets(1)
Dim column2 As Range: Set column = ws2.Sheets(1).Columns(3) 'this column will be filled as the macro is used each time
For Each cell In column.Cells
If cell.Value = "" Then
???
Edited for clarification:
This code will go in the first workbook ("QuartalReport.xlsm"). Both workbooks have only one sheet.
The data in the first workbook has no table formatting, and it starts in row 3.
The data in the second workbook should begin with cell C2 (or any column in row 2), as the first row will be for the header (though like in the first workbook, it is unformatted). Save for this column, the worksheet will be empty.
The objective is to copy the value in the cell in column B of the first workbook if the cell in the same row in column A is empty. For example if cells A3 through A5 in "QuartalReport.xlsm contain values, the rows should altogether be skipped. But if A6 is blank, then the value of whatever is in B6 should be copied to the next empty row (being the first case, C2) in "ClientList.xlsm". If the next empty cell is in A12, then B12 should be copied to C3. As such the column in the second workbook will have no empty rows between data.
A VBA Lookup: Copy Matches Consecutively
Option Explicit
Sub CopyMatchesConsecutively()
' Reference the source range ('srg').
Dim swb As Workbook: Set swb = ThisWorkbook
Dim sws As Worksheet: Set sws = swb.Worksheets(1)
Dim sfrrg As Range: Set sfrrg = sws.Range("A3:B3") ' first row range
Dim srg As Range, srCount As Long
With sfrrg
' '.Resize(sws.Rows.Count - .Row + 1)' is 'A3:B1048576' (or 'A3:B65536')
Dim slCell As Range: Set slCell = .Resize(sws.Rows.Count - .Row + 1) _
.Find("*", , xlFormulas, , xlByRows, xlPrevious)
If slCell Is Nothing Then Exit Sub ' no data
srCount = slCell.Row - .Row + 1
Set srg = .Resize(srCount)
End With
' Write the values from the source range to an array ('Data').
Dim Data(): Data = srg.Value
' Write the results to the top of the first column of the array.
Dim sr As Long, dr As Long
For sr = 1 To srCount
If IsEmpty(Data(sr, 1)) Then ' empty
' Or:
'If Len(CStr(Data(sr, 1))) = 0 Then ' blank e.g. '=""' (includes empty)
dr = dr + 1
Data(dr, 1) = Data(sr, 2)
End If
Next sr
' The results are in the rows from 1 to 'dr' of the first column.
' Reference the destination range ('drg').
Dim dwb As Workbook: Set dwb = Workbooks("ClientList.xlsm")
Dim dws As Worksheet: Set dws = dwb.Worksheets(1)
Dim dfCell As Range: Set dfCell = dws.Range("C2")
Dim drg As Range: Set drg = dfCell.Resize(dr) ' single-column of size 'dr'
' Write the results to the destination range.
drg.Value = Data ' write
drg.Resize(dws.Rows.Count - drg.Row - dr + 1).Offset(dr).Clear ' clear below
' Inform.
MsgBox "Matches copied consecutively.", vbInformation
End Sub
Related
I'm trying to copy a range to the first empty row on the next sheet.
But sometimes there is only 2 rows with values and other times there are 5,6 or 7 rows.
I have this for now:
Private Sub test()
Application.ScreenUpdating = False
Dim copySheet As Worksheet
Dim pasteSheet As Worksheet
Set copySheet = Worksheets("Blad1")
Set pasteSheet = Worksheets("Games")
copySheet.Range("AG4:AS13").Copy
pasteSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
It works to get it on the next sheet, but it seems to always take the empty cells that were pasted earlier into account when pasting.
So the first time I click it, I get say 2 filled rows, and 6 empty rows pasted, the next time, it pastes the 2 full rows on the 9th row instead of on the 3rd row.
The empty rows on sheet 1 do hold formulas, but they are not present in the destination cells after pasting.
It does do it's jobs when I select those empty cells, press 'delete', and the next time I use the macro, it does paste it on the 3rd row.
Any ideas how to solve this?
Tried looking up a solution, but nothing that really worked. I might have been searching in the wrong direction, so that's why I came here.
Copy Values (Empty vs Blank)
You have copied blank cells which are not empty and End(xlUp) detects them.
Before using the following, which will not copy blank cells, select the range from the first row below the last row with data to the bottom of the worksheet and press Del to get rid of any blank cells.
Sub CopyValues()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Sheets("Blad1")
Dim srg As Range: Set srg = sws.Range("AG4:AS13")
Dim scCount As Long: scCount = srg.Columns.Count
Dim dws As Worksheet: Set dws = wb.Sheets("Games")
Dim dfCell As Range: Set dfCell = dws.Range("A2")
Dim dlCell As Range
With dfCell
With .Resize(dws.Rows.Count - .Row + 1, dws.Columns.Count - .Column + 1)
Set dlCell = .Find("*", , xlFormulas, , xlByRows, xlPrevious)
End With
If Not dlCell Is Nothing Then
Set dfCell = .Offset(dlCell.Row - .Row + 1)
End If
End With
Dim drrg As Range: Set drrg = dfCell.Resize(, scCount)
Dim srrg As Range
For Each srrg In srg.Rows
If Application.CountBlank(srrg) < scCount Then
drrg.Value = srrg.Value
Set drrg = drrg.Offset(1)
End If
Next srrg
MsgBox "Values copied.", vbInformation
End Sub
So I have 6 Rows that I want to copy in to another sheet.
My problem is that the first row from sheet "data" copies and pastes correctly on sheet "blue" row 2.
But on the second loop, row two from sheet "data" copies and pastes on sheet "blue" also on row 2.
Then on the third loop, same thing happens.
Finaly when the loop finishes I only have the last row from sheet "data" pasted on sheet "blue" on row 2.
I guess the problem is, my line of code LastRowBlue isint updating loop by loop.
I know I can copy the whole thing with out loop, but this is an example for a bigger exercise.
¿Any Ideas? I almost got it!
Sub CopyPasteInOtherSheetWithLoop()
Dim BallsColorList As Range
Dim LastRowBallsColorList As Integer
Dim LastRowBlue As Integer
LastRowBallsColorList = Cells(Rows.Count, "B").End(xlUp).Row
Set BallsColorList = Range(Cells(2, "B"), Cells(LastRowBallsColorList, "B"))
For Each Ball In BallsColorList
LastRowBlue = Sheets("blue").Cells(Rows.Count).End(xlUp).Row + 1
Range(Ball.Offset(0, -1), Ball.Offset(0, 2)).Copy Sheets("blue").Cells(LastRowBlue, "A")
Next
End Sub
enter image description here
enter image description here
Copy Using a Loop
Here is one of the countless ways you could do it.
By introducing more object variables (workbook-worksheet-range), it clearly shows what is what and more importantly, where it is located.
Rename the variables if you feel they're too generic.
Sub CopyUsingLoop()
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Source
Dim sws As Worksheet: Set sws = wb.Worksheets("Data")
Dim scrg As Range
Set scrg = sws.Range("B2", sws.Cells(sws.Rows.Count, "B").End(xlUp))
Dim srg As Range: Set srg = scrg.EntireRow.Columns("A:D")
' Destination
Dim dws As Worksheet: Set dws = wb.Worksheets("Blue")
Dim dCell As Range
Set dCell = dws.Cells(dws.Rows.Count, "A").End(xlUp)
' Loop.
Dim sCell As Range
Dim sr As Long
Dim dr As Long
For Each sCell In scrg.Cells
sr = sr + 1
If StrComp(CStr(sCell.Value), "Blue", vbTextCompare) = 0 Then
dr = dr + 1
srg.Rows(sr).Copy dCell.Offset(dr)
End If
Next sCell
End Sub
I have an extensive workbook with around 500 custom named worksheets that have been created by a macro that has manipulated data from a core dataset. All worksheets follow an identical format.
Within the range QG27:SO27 on every one of these ~500 worksheets there is a formula that shows "TRUE" if all the above cells meet a certain criteria, otherwise they are blank
My challenge is to collate the "TRUE" data to a separate sheet named "COLLATED TRUE VALUES". By scanning through QG27:SO27 on each worksheet, if a cell in QG27:SO27 contains "TRUE" then copy that column from row 1:27 and paste to C2 of sheet named "COLLATED TRUE VALUES" and copy/paste the sheet name it was extracted from into C1. Each additional "TRUE" encountered will copy/paste the same corresponding data to the next column in the "COLLATED TRUE VALUES" sheet and continue through all worksheets
I have considered a loop through the range that may contain "TRUE" and step through each of the 500 sheets but his would be a slow process and I expect to need to reuse this type of scenario with many other workbooks.
I would like some help creating a macro that can collate the required date in the most efficient way
Copy Columns of a Range With Condition
Option Explicit
Sub CollateTrueValues()
' Define constants.
' Source
Const srgAddress As String = "QG1:SO27"
Const sBoolean As Boolean = True
' Destination
Const dName As String = "COLLATED TRUE VALUES"
Const dFirstCellAddress As String = "C1"
' Reference the workbook ('wb').
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Reference the destination worksheet ('dws').
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
' Reference the destination first cell ('dfCell').
Dim dfCell As Range: Set dfCell = dws.Range(dFirstCellAddress)
' Write the number of rows and columns to variables ('rCount', 'cCount').
Dim rCount As Long
Dim cCount As Long
With dws.Range(srgAddress)
rCount = .Rows.Count
cCount = .Columns.Count
End With
' Declare additional variables.
Dim sws As Worksheet
Dim srg As Range
Dim sValue As Variant
Dim Data As Variant
Dim sName As String
Dim r As Long
Dim sc As Long
Dim dc As Long
' Loop...
For Each sws In wb.Worksheets
' Check if it's not the destination worksheet.
If Not sws Is dws Then
' Write the source worksheet name to a variable ('sName').
sName = sws.Name
' Write the source data to a 2D one-based array ('Data').
Data = sws.Range(srgAddress).Value
' Write the matching data to the left 'dc' columns of the array.
For sc = 1 To cCount
sValue = Data(rCount, sc)
If VarType(sValue) = vbBoolean Then
If sValue = sBoolean Then
dc = dc + 1
For r = 1 To rCount
Data(r, dc) = Data(r, sc)
Next r
'Else ' is not a match (True), do nothing
End If
'Else ' is not a boolean; do nothing
End If
Next sc
' Write the matching data to the destination worksheet.
If dc > 0 Then
With dfCell.Resize(, dc)
.Value = sName ' write worksheet name
.Offset(1).Resize(rCount).Value = Data ' write data
End With
Set dfCell = dfCell.Offset(, dc) ' next first destination cell
dc = 0
'Else ' no matching (True) values; do nothing
End If
'Else ' it's the destination worksheet; do nothing
End If
Next sws
' Clear to the right.
dfCell.Resize(rCount + 1, dws.Columns.Count - dfCell.Column + 1).Clear
' Inform.
MsgBox "True values collated.", vbInformation
End Sub
I need some help. I have two columns: A and B. Column A and Column B have the following headers "Status" and "State". A filter has been applied to select "down" from a choice of "up" and "down" in Column A. When Column A is filtered some blank cells are revealed in Column B after some cells in Column B is cleared. The amount of data in the sheet varies and the position of these blanks also vary. I will like to fill down these blank cells in Column B using the values in visible cells only (not from the values in the hidden cells). Can someone help me edit this code?
In the pic above SO will fill down from 50476 to 50492 without erasing the values in the hidden cells.
Sub Filldownvisiblecells ()
Dim ws as worksheet
Dim dl as long
Dim rg as range
ws = Workbooks("Book1.xlsm"). Worksheets("Sheet1")
dl = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'Filter Column A by Down
ws.Range("A1").AutoFilter Field:=1, Criteria1:="Down"
'Clearing States in Column B (This action generates blanks that I will like to filldown from visible cells NOT hidden cells)
ws.Range("B2:B" & dl).SpecialCells(xlCellTypeVisible).Select
For Each rg In Selection.Cells
If rg.Text = "R1" Or rg.Text = "R2" Or rg.Text = "UT" Then
rg.ClearContents
End If
Next rg
'Select Filldown Range in Column B
ws.Range("B2:B" & dl). SpecialCells(xlCellTypeVisible).Select
'Filldown Blanks in Column X
For Each rg In Selection.Cells
If rg.Value = "" Then
rg.FillDown
End If
Next rg
End Sub
Fill Down With Visible Cells' Values (AutoFilter)
Option Explicit
Sub FillDownVisible()
Const wsName As String = "Sheet1"
Const fRow As Long = 1 ' First Row
Const fCol As String = "A" ' Filter Column
Const fCriteria As String = "Down" ' Filter Criteria
Const dCol As String = "B" ' Destination Column
Dim ws As Worksheet
' The Workbook Containing This Code ('ThisWorkbook')
Set ws = ThisWorkbook.Worksheets(wsName)
' An Open Workbook
'Set ws = Workbooks("Book1.xlsm").Wordksheets(wsname)
' Possibly Closed Workbook (Needs the Full File Path)
'Set ws = Workbooks.Open("C:\Test\Book1.xlsm").Worksheets(wsName)
' Clear possible previous ('active') filter.
If ws.AutoFilterMode Then
ws.AutoFilterMode = False
End If
' Create a reference to the Filter Range ('frg').
Dim lRow As Long: lRow = ws.Cells(ws.Rows.Count, fCol).End(xlUp).Row
Dim frg As Range: Set frg = ws.Cells(fRow, fCol).Resize(lRow - fRow + 1)
' Create a reference to the Destination Data Range (no headers).
Dim ddrg As Range: Set ddrg = frg.EntireRow.Columns(dCol) _
.Resize(frg.Rows.Count - 1).Offset(1)
' Filter Filter Range.
frg.AutoFilter Field:=1, Criteria1:=fCriteria
' Create a reference to the Destination Range ('drg').
Dim drg As Range: Set drg = ddrg.SpecialCells(xlCellTypeVisible)
Dim dCell As Range ' Current Destination Cell
Dim pValue As Variant ' Previous Value
Dim cValue As Variant ' Current Value
' Loop through the cells of the Destination Range.
For Each dCell In drg.Cells
cValue = dCell.Value
Select Case UCase(CStr(cValue))
Case "R1", "R2", "UT", ""
dCell.Value = pValue
Case Else
pValue = cValue
End Select
Next dCell
ws.AutoFilterMode = False
End Sub
I want to paste a column selection (a2:a200) to the next available column to the right.
I am having trouble doing this.
Here I am copying the data from Tables and pasting it in the last available column to the right.
Sub CopyMonthData() Worksheets("Tables").Range("d2:d200").Copy _
Worksheets("SalesInvoicesMonth").Range("a" & Columns.Count).End(xlToLeft).Offset(1, 0) End Sub
How can I make this work?
You could use UsedRange instead.
Sub CopyMonthData()
Dim iLastCol as Integer
With Worksheets("SalesInvoicesMonth")
iLastCol = .UsedRange.Column + .UsedRange.Columns.Count - 1
Worksheets("Tables").Range("d2:d200").Copy .Cells(1,iLastCol + 1)
End With
End Sub
Declaring iLastCol helps you understand how to calculate the value but the variable is not required. You could replace it in the copy function by its actual value --> - 1 and + 1 cancel each other, so you get .Cells(1,.usedRange.Column + .UsedRange.Columns.Count) as destination range.
Copy to the Next Available Column
A Quick Fix (End)
I'm assuming that you want to copy the column range D2:D200 in the source worksheet (Tables) to the second row of the column after (next to) the last non-empty column of the destination worksheet (SalesInvoicesMonth) and that both worksheets reside in the workbook containing this code (ThisWorkbook). Also, I'm assuming that all columns in the destination worksheet have headers in the first row, which will be the row used to calculate the column number.
Sub CopyMonthDataSimple()
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim sws As Worksheet: Set sws = wb.Worksheets("Tables")
Dim dws As Worksheet: Set dws = wb.Worksheets("SalesInvoicesMonth")
sws.Range("D2:D200").Copy _
dws.Cells(1, dws.Columns.Count).End(xlToLeft).Offset(1, 1)
End Sub
The first 1 in .Offset(1, 1) means the second row, while the second 1 means the column next to the column of the last (not hidden) header cell.
A More Flexible Solution (Find)
The following will copy the column range from the given cell (sFirst) to the bottom-most non-empty cell of the column of the source worksheet to the destination worksheet starting with the cell in the given row (dfrow) of the column after the last non-empty column.
Adjust (play with) the values in the constants section.
Sub CopyMonthData()
' Constants & Workbook
' Source
Const sName As String = "Tables"
Const sFirst As String = "D2"
' Destination
Const dName As String = "SalesInvoicesMonth"
Const dfRow As Long = 2
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Attempt to create a reference to the Source Column Range ('srg').
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim sfCell As Range: Set sfCell = sws.Range(sFirst)
Dim sfOffset As Long: sfOffset = sfCell.Row - 1
Dim slCell As Range
' The bottom-most non-empty cell in the Source Column.
Set slCell = sfCell.Resize(sws.Rows.Count - sfOffset) _
.Find("*", , xlFormulas, , , xlPrevious)
If slCell Is Nothing Then
MsgBox "The range from the 'First Source Cell' to the bottom-most " _
& "cell of the 'Source Column' is empty.", _
vbCritical, "CopyMonthData"
Exit Sub
End If
' The following...
Dim srCount As Long: srCount = slCell.Row - sfOffset
Dim srg As Range: Set srg = sfCell.Resize(srCount)
' ... is another way of doing...
'Dim srg As Range: Set srg = sws.Range(sfCell, slCell)
' Attempt to create a reference
' to the Destination First Cell Range ('dfCell').
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
Dim dlCell As Range
' The bottom-most non-empty cell in the last non-empty column.
Set dlCell = dws.Cells.Find("*", , xlFormulas, , xlByColumns, xlPrevious)
Dim dCol As Long
If dlCell Is Nothing Then ' The Destination Worksheet is empty.
dCol = 1
Else
If dlCell.Column = dws.Columns.Count Then
MsgBox "The 'Destination Last Column' is not empty.", _
vbCritical, "CopyMonthData"
Exit Sub
Else
dCol = dlCell.Column + 1
End If
End If
Dim dfCell As Range: Set dfCell = dws.Cells(dfRow, dCol)
' Copy
' Copy values, formats and formulas.
srg.Copy dfCell
' Or copy values (only) by assignment (more efficient (faster)).
'dfCell.Resize(srCount).Value = srg.Value
dfCell.EntireColumn.AutoFit
End Sub