Copy rows (not entire row) from one sheet to another - excel

I am having trouble with the below code. "Backend" is the Source Sheet and "Availability" is the Target sheet. Any help is appreciated.
Sub CopyA()
Dim lr As Long, lr2 As Long, r As Long
lr = Sheets("Backend").Cells(Rows.Count, "AB").End(xlUp).Row
lr2 = Sheets("Availability").Cells(Rows.Count, "A").End(xlUp).Row
For r = lr To 2 Step -1
If Range("Backend!AB" & r).Value = "A" Then
Range("Availability!A" & lr2 + 1 & ":C" & lr2 + 1) =
Range("Backend!V" & r & ":X" & r).Value2
lr2 = Sheets("Availability").Cells(Rows.Count, "A").End(xlUp).Row
End If
Next r
End Sub

Based on your code I think you are trying to copy columns V:X from sheet Backend if column AB = A and paste the data into column A of sheet Availability.
This code achieves that:
Sub CopyData()
Dim lastRow As Long, rw As Long
lastRow = Sheets("Backend").Cells(Rows.Count, "AB").End(xlUp).Row
With Worksheets("Backend")
For rw = lastRow To 2 Step -1
If .Range("AB" & rw) = "A" Then
pasteRow = Worksheets("Availability").Cells(Rows.Count, "A").End(xlUp).Row + 1
Range("V" & rw & ":X" & rw).Copy Destination:=Worksheets("Availability").Range("A" & pasteRow & ":C" & pasteRow)
End If
Next rw
End With
End Sub
In your original code you are looping backwards with Step -1. A consequence of this is that the data pasted into Availability will be in reverse order. If you want the pasted data to appear in the order it is found on backend then use this code instead:
Sub CopyData2()
Dim copyRng As Range, cl As Range
Set copyRng = Worksheets("Backend").Range("AB2:AB" & Worksheets("Backend").Cells(Rows.Count, "AB").End(xlUp).Row)
With Worksheets("Availability")
For Each cl In copyRng
If cl = "A" Then
pasteRow = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
Worksheets("Backend").Range("V" & cl.Row & ":X" & cl.Row).Copy Destination:=.Range("A" & pasteRow & ":C" & pasteRow)
End If
Next cl
End With
End Sub

Related

VBA - sort the data from excel

I'm having an case what i don't know how to deal with that, can someone suggest or give me some idea to solve it ?
Summary: I have an Excel file with 3 columns (Name, user , password), this is an example. As you can see in column A , there are 2 cell with name jack , 1 is his user ID (row 2) , and the other is his password. I wish they can stored in the same row , sth like that cell A2 is jack , cell B2 is his user name (jck), and C2 is his pwd (123).
my code as below
Sub test()
Dim last_row As Long
Dim sh As Worksheet
Dim sh2 As Worksheet
Dim wb As Workbook
Set wb = ThisWorkbook
Set sh = wb.Sheets(1)
Set sh2 = wb.Sheets(2)
Dim rng As Range
last_row = sh.Range("A" & Rows.Count).End(xlUp).Row
last_row2 = sh2.Range("A" & Rows.Count).End(xlUp).Row
MsgBox last_row
For i = 2 To last_row - 1
For j = i + 1 To last_row
If sh.Range("A" & i).Value = sh.Range("A" & j).Value Then
If IsEmpty(Range("B" & i)) Then
sh2.Range("A" & i & ":C" & i).Value = sh.Range("A" & i & ":C" & i).Value
sh2.Range("B" & i).Value = sh.Range("B" & j).Value
End If
If IsEmpty(Range("C" & i)) Then
sh2.Range("A" & i & ":C" & i).Value = sh.Range("A" & i & ":C" & i).Value
sh2.Range("C" & i).Value = sh.Range("C" & j).Value
End If
End If
Next j
Next i
End Sub
Could you please help look ? Any assist will be appreciated.
Your main issue is that you use the same row counter for Sheet2 as you do for Sheet1. Since you will end up with half the number of rows with data in Sheet2, that will result in gaps in Sheet2. You will need a seperate row counter for Sheet2
Another issue is you have several unqualified Range references, so whether this works or not will depend on which sheet is active.
A third issue is you haven't declared all your variables.
You code, refactored
Sub test()
Dim last_row As Long
Dim last_row2 As Long
Dim sh As Worksheet
Dim sh2 As Worksheet
Dim wb As Workbook
Dim rng As Range
Dim i As Long, j As Long
Dim rw2 As Long
Set wb = ThisWorkbook
Set sh = wb.Sheets(1)
Set sh2 = wb.Sheets(2)
last_row = sh.Range("A" & sh.Rows.Count).End(xlUp).Row
last_row2 = sh2.Range("A" & sh2.Rows.Count).End(xlUp).Row
'MsgBox last_row
rw2 = 1
For i = 2 To last_row - 1
For j = i + 1 To last_row
If sh.Range("A" & i).Value = sh.Range("A" & j).Value Then
If IsEmpty(sh.Range("B" & i)) Or IsEmpty(sh.Range("C" & i)) Then
rw2 = rw2 + 1
sh2.Range("A" & rw2 & ":C" & rw2).Value = sh.Range("A" & i & ":C" & i).Value
If IsEmpty(sh.Range("B" & i)) Then
sh2.Range("B" & rw2).Value = sh.Range("B" & j).Value
ElseIf IsEmpty(sh.Range("C" & i)) Then
sh2.Range("C" & rw2).Value = sh.Range("C" & j).Value
End If
End If
End If
Next j
Next i
End Sub

Select the first n values of columns in a row without using select

Hey I just found a great code on this site which allows you to dynamically select the n bottom values of columns in a row. with the following code:
Dim LastRow, a As Long
LastRow = Cells(Rows.Count, "K").End(xlUp).Row
Range("K" & LastRow - 2 & ":K" & LastRow).Copy
My code above selects the 2 values at the bottom. Is there any way I can select the two top values of columns in a cell? I tried to do it brainless by modifying my code to
Dim LastRow, a As Long
firstRow = Cells(Rows.Count, "K").End(xlDown).Row
Range("K" & firstRow + 2 & ":K" & firstRow).Copy
However, that doesn't seem to do the job. Furthermore, in my row columns where I want to select the first 10 values there is a string/text above, how do I deal with that?
Dim Firstrow As Long
Dim RowsToCopy As Long
' First row is 2 if there is a header text, else 1.
Firstrow = 2
RowsToCopy = 2
' Copy 2 rows starting at 'Firstrow'
Range("K" & Firstrow & ":K" & Firstrow + (RowsToCopy - 1)).Copy
Please, try the next way:
Sub testFirstTwoRows()
Dim sh As Worksheet, firstR As Long
Set sh = ActiveSheet
firstR = sh.Range("K1").End(xlDown).row
If WorksheetFunction.CountA(sh.Range("K1:K" & firstR - 1)) > 0 Or _
firstR = sh.rows.count Then
firstR = 1
End If
Range("K" & firstR & ":K" & firstR + 1).Copy
End Sub

How to loop through all filter options in VBA?

I'd like to use a loop to go through each of the criteria in a filter, then calculate and output averages. My code below calculates the averages and outputs them on the next empty line of the second sheet, but unfortunately, this only works for the first filter selection. After each new iteration of the loop, nothing happens. Can anyone help?
source data
output
Option Explicit
Sub avg()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim cell As Range
Dim lastrow As Long
Dim RowCount As Long
Dim rng1 As Range
Dim nextrow As Long
Set ws1 = Worksheets("Sheet1")
Set ws2 = Worksheets("Sheet2")
lastrow = ws1.Cells(Rows.Count, 1).End(xlUp).Row
RowCount = ws2.Cells(Rows.Count, 1).End(xlUp).Row
Set rng1 = ws1.Range("G2:G" & lastrow)
For Each cell In rng1.SpecialCells(xlCellTypeVisible)
With ws1.AutoFilter.Range
ws2.Range("A" & RowCount + 1) = ws1.Range("B" & .Offset(1, 0).SpecialCells(xlCellTypeVisible)(1).Row).Value2
ws2.Range("B" & RowCount + 1) = ws1.Range("F" & .Offset(1, 0).SpecialCells(xlCellTypeVisible)(1).Row).Value2
End With
ws2.Range("C" & RowCount + 1) = Application.WorksheetFunction.Average(ws1.Range("Y2:Y" & lastrow & ",Z2:Z" & lastrow & ",AA2:AA" & lastrow _
& ",AD2:AD" & lastrow & ",AE2:AE" & lastrow & ",AI2:AI" & lastrow & ",AK2:AK" & lastrow & ",AL2:AL" & lastrow).SpecialCells(xlCellTypeVisible))
ws2.Range("D" & RowCount + 1) = Application.WorksheetFunction.Average(ws1.Range("AF2:AF" & lastrow & ",AM2:AM" & lastrow & ",AP2:AP" & lastrow _
& ",AQ2:AQ" & lastrow & ",AR2:AR" & lastrow & ",AS2:AS" & lastrow & ",AT2:AT" & lastrow & ",AU2:AU" & lastrow).SpecialCells(xlCellTypeVisible))
ws2.Range("E" & RowCount + 1) = Application.WorksheetFunction.Average(ws1.Range("AW2:AW" & lastrow & ",AX2:AX" & lastrow & ",AY2:AY" & lastrow).SpecialCells(xlCellTypeVisible))
Next cell
End Sub
Few changes made in your macro. Note the newly added array for unique values of filter criteria and loop changed from each cells to array. lastrow and RowCount variables replaced by lastrow1 and lastrow2.
Sub avg()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws1 As Worksheet, ws2 As Worksheet
Dim cell As Range, rng1 As Range, rng1Crt As Range
Dim lastrow1 As Long, lastrow2 As Long, arr As Variant
Set ws1 = wb.Worksheets("Sheet1")
Set ws2 = wb.Worksheets("Sheet2")
lastrow1 = ws1.Cells(Rows.Count, 1).End(xlUp).Row
Set rng1 = ws1.Range("G1:G" & lastrow1)
rng1.AdvancedFilter Action:=xlFilterInPlace, Unique:=True
Set rng1Crt = rng1.Cells.SpecialCells(xlCellTypeVisible)
'Populating array with filter criteria values
ReDim arr(0 To rng1Crt.Cells.Count - 1)
i = 0
For Each cell In rng1Crt.Cells
arr(i) = cell.Value
i = i + 1
Next
ws1.ShowAllData
rng1.AutoFilter
For i = 1 To UBound(arr)
lastrow2 = ws2.Cells(Rows.Count, 1).End(xlUp).Row
rng1.AutoFilter Field:=1, Criteria1:=arr(i)
With ws1.AutoFilter.Range
ws2.Range("A" & lastrow2 + 1) = ws1.Range("B" & .Offset(1, 0).SpecialCells(xlCellTypeVisible)(1).Row).Value2
ws2.Range("B" & lastrow2 + 1) = ws1.Range("F" & .Offset(1, 0).SpecialCells(xlCellTypeVisible)(1).Row).Value2
End With
ws2.Range("C" & lastrow2 + 1) = Application.WorksheetFunction.Average(ws1.Range("Y2:Y" & lastrow1 & ",Z2:Z" & lastrow1 & ",AA2:AA" & lastrow1 _
& ",AD2:AD" & lastrow1 & ",AE2:AE" & lastrow1 & ",AI2:AI" & lastrow1 & ",AK2:AK" & lastrow1 & ",AL2:AL" & lastrow1).SpecialCells(xlCellTypeVisible))
ws2.Range("D" & lastrow2 + 1) = Application.WorksheetFunction.Average(ws1.Range("AF2:AF" & lastrow1 & ",AM2:AM" & lastrow1 & ",AP2:AP" & lastrow1 _
& ",AQ2:AQ" & lastrow1 & ",AR2:AR" & lastrow1 & ",AS2:AS" & lastrow1 & ",AT2:AT" & lastrow1 & ",AU2:AU" & lastrow1).SpecialCells(xlCellTypeVisible))
ws2.Range("E" & lastrow2 + 1) = Application.WorksheetFunction.Average(ws1.Range("AW2:AW" & lastrow1 & ",AX2:AX" & lastrow1 & ",AY2:AY" & lastrow1).SpecialCells(xlCellTypeVisible))
Next
End Sub

identify the last used cell and paste below

I'm a total novice with VBA. I have the following code which does a matching exercise and then pastes the relevant values into col. B. my issue is each time the code is used the col will change how can I add this to the module so that it looks for the last cell used in row 1 and pastes the values below.
Sub TransferData()
Dim i As Long, j As Long, lastrow1 As Long, lastrow2 As Long
Dim myname As String
Application.ScreenUpdating = False
lastrow1 = Sheets("Input Sheet").Range("B" & Rows.Count).End(xlUp).Row
For i = 2 To lastrow1
myname = Sheets("Input Sheet").Cells(i, "B").Value
Sheets("Data").Activate
lastrow2 = Sheets("Data").Range("A" & Rows.Count).End(xlUp).Row
For j = 2 To lastrow2
If Sheets("Data").Cells(j, "A").Value = myname Then
Sheets("Input Sheet").Activate
Sheets("Input Sheet").Cells(i, "c").Copy
Sheets("Data").Activate
Sheets("Data").Cells(j, "B").Select
ActiveSheet.PasteSpecial
End If
Next j
Application.CutCopyMode = False
Next i
Application.ScreenUpdating = True
End Sub
any assistance with this would be appreciated.
You can replace your second For j = 2 To lastrow2 with the Match function.
Also, there is no need to Activate the sheets back and fourth all the time, just use fully qualified Ranges instead.
Code
Option Explicit
Sub TransferData()
Dim i As Long, j As Long, lastrow1 As Long, lastrow2 As Long
Dim myname As String
Dim MatchRng As Range
Application.ScreenUpdating = False
j = 2
With Sheets("Input Sheet")
lastrow1 = .Range("B" & .Rows.Count).End(xlUp).Row
' the 2 lines bellow should be outisde the loop
lastrow2 = Sheets("Data").Range("A" & Sheets("Data").Rows.Count).End(xlUp).Row
Set MatchRng = Sheets("Data").Range("A2:A" & lastrow2)
For i = 2 To lastrow1
myname = .Range("B" & i).Value
If Not IsError(Application.Match(myname, MatchRng, 0)) Then '<-- if successful Match
Sheets("Data").Range("B" & j).Value = .Range("C" & i).Value
j = j + 1
End If
Application.CutCopyMode = False
Next i
End With
Application.ScreenUpdating = True
End Sub

macro to create multiple sub totals in one column

Can anyone help me with this macro to create multiple sub totals in one column? Any help would be great. I have a group of numbers in column Y. which begins at row 16.
The data is listed on every three lines until the end of that section then there is a gap of around thirty lines then it beings again. I want to create a macro to count how many numbers >45 in each section. Put the total 2 rows below the last data point of each section. In column X on the same row place Number>45
Sub Sample()
Dim result As Long, firstrow As Long, lastrow As Long
Dim ws As Worksheet
Dim rng As Range
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
'~~> Find Lastrow in Col Y
lastrow = .Range("Y" & .Rows.Count).End(xlUp).Row
'~~> Set First row
firstrow = 16
'~~> Set your range
Set rng = .Range("Y" & firstrow & ":Y" & lastrow)
'~~> Put relevant values
.Range("x" & lastrow + 2).Value = "Total>45"
.Range("y" & lastrow + 2).Value = _
Application.WorksheetFunction.CountIf(rng, ">45")
End With
End Sub
try the below procedure
and loop backwards to ROW=1 like this:
Sub setTotals()
Dim iRow As Integer
Dim iLastRow As Integer
Dim sFormulaTargetAddress As String
iLastRow = ActiveSheet.Range("Y" & ActiveSheet.Rows.Count).End(xlUp).Row
iRow = iLastRow
Do Until iRow = 1
If Range("Y" & iRow).Value <> "" Then
'
' define the section
sFormulaTargetAddress = "Y" & Range("Y" & iRow).End(xlUp).Row & ":Y" & iRow & ""
'
' Put in the COUNTIF > 45 of the current section...
'
Range("Y" & iRow + 2).Formula = "=COUNTIF(" & sFormulaTargetAddress & ","">45"")"
' '
'Range("X" & iRow + 2).Formula = "=COUNTIF(" & sFormulaTargetAddress & ","">45"")"
Range("X" & iRow + 2).value="Numbers > 45"
'
' find the next section
iRow = Range("Y" & iRow).End(xlUp).Row
If Range("Y" & iRow) <> "" Then iRow = Range("Y" & iRow).End(xlUp).Row
Else
iRow = Range("Y" & iRow).End(xlUp).Row
End If
Loop
End Sub
HTH
Philip

Resources