VBA Copy and Paste to another sheet - vba

I am new to programming and |I would like some help with the following:
I need a code that when it reads in cells(x,3)="wall" then for every next row until it "hits" another element, that it to say until cells(x+1,3)<>"", it copies the values of cells A:E of that row to another sheet if these satisfy a specific condition. The code will somehow start like that:
If Cells(x, 3) = "wall" Then
Do Until Cells(x + 1, 2) <> ""
If Cells(x + 1, 4) <> "m2" Then
......
x=x+1
Loop
I would like some help with the part of the code in between.

Try the code below. Make sure that it's looking at the correct cells for your conditions.
Option Explicit
Sub copyCells()
'Some variables to keep track of where we are on the sheets
Dim x As Integer
Dim lastRow As Integer
Dim i As Integer
Sheets("Sheet1").Select
Range("A1").Select
'I used 18 rows in my test set. You'll want to change this to fit your data.
lastRow = 18
i = 1
For x = 1 To lastRow
'Check for the first condition
If Cells(x, 3) = "wall" Then
'Move to the next row
x = x + 1
'Check that this is a row we want to copy
'and we haven't reached the end of our data
Do While Cells(x, 2) = "" And x < lastRow
'Check the second condition
If Cells(x, 4) <> "m2" Then
'Copy and paste to the second sheet
Range("A" & x & ":E" & x).Copy
Sheets("Sheet2").Select
Range("A" & i).Select
ActiveSheet.Paste
'Increment i to keep track of where we are on the second sheet
i = i + 1
End If
'Go back to checking the first sheet
x = x + 1
Sheets("Sheet1").Select
Range("A" & x).Select
Loop
End If
Next x
Application.CutCopyMode = False
End Sub

Related

Select 2 rows of data to cut, once cell containing "1" is found

Ok, so im a very basic user..
Im using the "If" function to find dips in data, when a dip is found column E shows "1", all others are "0". But I need that whole row with the "1" and the next row, even if it has a "0" or "1".
I currently have this:
If ActiveCell.Value = "1" Then
Selection.EntireRow.Cut
Sheets("Sheet2").Select
lMaxRows = Cells(Rows.Count, "A").End(xlUp).Row
Range("A" & lMaxRows + 1).Select
ActiveSheet.Paste
Sheets("Sheet1").Select
Else
So what I need is to tell it to select the row containing "1" (which it already does), as well as the next row.... the rest should cut and append the data to another worksheet.
Great post on alternatives and more reliable methods than ".Select". After reading, you can adjust your code. How to avoid using Select in Excel VBA
To answer your question, replace
Selection.EntireRow.Cut
with
Range(Selection.EntireRow, Selection.Offset(1, 0).EntireRow).Cut
This should get you a good start, you'll need to add some code to not cut all 5 rows above if some of the are blank because they've already been cut or you could remove blank rows on sheet 2 once this code is done.
Sub GetDipsData()
Dim i As Long
Dim c As Long
Dim LastConsecutiveDip As Long
Dim vLastRow As Long
Sheets("Sheet1").Activate
vLastRow = Cells(Rows.Count, "E").End(xlUp).Row
Application.ScreenUpdating = False
For i = 2 To vLastRow
If Cells(i, "E") = 1 Then
s2LastRow = Sheets("Sheet2").Cells(Rows.Count, "E").End(xlUp).Row
For c = i + 1 To vLastRow
If Cells(c, "E") = 1 Then
LastConsecutiveDip = c
Else
Exit For
End If
Next
If c <> i + 2 Then
'copy 5 above and 5 below
If i < 6 Then
Range(Rows(2), Rows(c).Offset(5, 0).EntireRow).Cut Sheets("Sheet2").Range("A" & s2LastRow)
ElseIf c + 5 > vLastRow Then
Range(Rows(i).Offset(-5, 0), Rows(vLastRow).EntireRow).Cut Sheets("Sheet2").Range("A" & s2LastRow)
Else
Range(Rows(i).Offset(-5, 0), Rows(c).Offset(5, 0).EntireRow).Cut Sheets("Sheet2").Range("A" & s2LastRow)
End If
i = c + 5
Else
'just copy 2 rows
If i + 1 > vLastRow Then
Rows(i).Cut Sheets("Sheet2").Range("A" & s2LastRow)
Else
Range(Rows(i), Rows(i).Offset(1, 0).EntireRow).Cut Sheets("Sheet2").Range("A" & s2LastRow)
i = i + 2
End If
End If
End If
Next
Application.ScreenUpdating = True
End Sub

Range with blank cells copy and pasted into single column

I am trying to copy and paste a range that includes blank cells into a single column on another sheet. I would like the blanks to be ignored.
Here is the Frankenstein code I am using at the moment it is slow and a bit cluncky picture included to better describe
I would like to expand on it so that multiple ranges can paste into the same column ie find the last cell with a value and paste into the next cell.
i have been told it should look something like this
'for r = 1 to 4
' for c = 1 to 8
' does rc have val,
' then copy to new sheet
' increment copy var
' increment c
' increment r
Sheets(Array("next record date")).Select
Range("G11:AZZ110").Select
If TypeName(Selection) = "Range" Then
If Selection.Count > 1 Then
If Selection.Count <= Selection.Parent.Rows.Count Then
vaCells = Selection.Value
ReDim vOutput(1 To UBound(vaCells, 1) * UBound(vaCells, 2), 1 To 1)
For j = LBound(vaCells, 2) To UBound(vaCells, 2)
For i = LBound(vaCells, 1) To UBound(vaCells, 1)
If Len(vaCells(i, j)) > 0 Then
lRow = lRow + 1
Sheets("Data").Select
Range("E2").Select
vOutput(lRow, 1) = vaCells(i, j)
Else
End If
Next i
Next j
Selection.ClearContents
Selection.Cells(1).Resize(lRow).Value = vOutput
End If
End If
End If
Thanks,
Jerome
Special cells constants method and paste transpose
Public Sub TransposeRange()
ThisWorkbook.Worksheets("next record date").Range("G11:AZ11").SpecialCells(xlCellTypeConstants, 23).Copy
ThisWorkbook.Worksheets("Data").Range("E2").PasteSpecial Paste:=xlValues, Transpose:=True
End Sub

Fibonacci Sequence that deletes even numbers VBA

Over the school holidays I was tasked with creating code that would output the Fibonacci sequence up to a certain number (in this case, the number I was given was 100000). Then, from that, I was ordered with deleting the cells that had even numbers, showing only cells that were odd. I have tried and tried many different method of doing both, but nothing seems to be working for me. Here is the code I was using:
Sub fib()
Dim x As Long
x = 100000
Range("A1") = 0
Range("A2") = 1
Do
If Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Value + _
Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Offset(-1, 0).Value >= x _
Then Exit Sub
Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Offset(1, 0).FormulaR1C1 = _
"=R[-1]C+R[-2]C"
Loop
For Each Cell In Range("A1:A30")
If Cell.Row Mod 2 = 0 Then
Rows(Cell.Row).ClearContents
End If
Next
Selection.SpecialCells(xlCellTypeBlanks).Select
Selection.EntireRow.Delete
End Sub
Now, I understand there may be a few problems with my code. The main one I see is in the first block, where instead of just inputting the numbers in to the cell, it instead inputs the way it would be calculated (for example, cell A10's value is just given as =A9+A8). I am not sure if this would cause an error in the second part of the code, where it looks for cell values so it can delete whether it is even. Could I please have some assistance on this matter? It would be much appreciated, as I've been struggling with it for the past few days now. Any help is appreciated! :)
Try the code below.
Sub fib()
Dim x As Long
Dim lRow As Long
x = 100000
Range("A1") = 0
Range("A2") = 1
Do
If Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Value + _
Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Offset(-1, 0).Value >= x _
Then Exit Sub
Range("A" & Range("A" & Rows.Count).End(xlUp).Row).Offset(1, 0).FormulaR1C1 = _
"=R[-1]C+R[-2]C"
Columns("A:A").Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Loop
With ActiveSheet
lRow = WorksheetFunction.Max(Range("A65536").End(xlUp).Row)
For i = lRow To 2 Step -1
If .Cells(i, "A") Mod 2 = 0 Then
Rows(i).Delete
End If
Next i
End With
End Sub
Generate 30 values using formulas, then freeze those values (remove formulas), then remove any even values or values that exceed the max:
Sub fib()
Dim xMax As Long: xMax = 100000
Range("A1").Value = 0: Range("A2").Value = 1
With Range("A3:A30")
.Formula = "=A1+A2" ' generate using formula
.Value = .Value ' remove formulas and freeze values
End With
' now remove even values and values that exceed the xMax
' Remember to iterate backward when the loop involves deleting
Dim i As Long
For i = Cells(Rows.count, "A").End(xlUp).Row To 3 Step -1
If Cells(i, "A").Value Mod 2 = 0 Or _
Cells(i, "A").Value > xMax Then Rows(i).Delete
Next
End Sub
All this code seems fancier than it needs to be. Does this work?
The Do While..Loop builds your sequence cell by cell in column A up to 100,000.
The For Loop then runs through the list cell by cell and deletes even numbers.
Sub Fib()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets(1)
Dim r As Long, x As Long, y As Long, z As Long, i As Long
Dim cell As Range
r = 1
x = 1
y = 0
z = 1
Do While z <= 100000
ws.Range("A" & r).Value = z
r = r + 1
z = x + y
y = x
x = z
Loop
For Each cell In ws.Range("A1", ws.Range("A1").End(xlDown))
If cell.Value Mod 2 = 0 Then cell.EntireRow.Delete
Next cell
End Sub

Merge+unmerge cells to normalize table based on first column; insert newlines between merged content

I have an Excel sheet with cells in some columns merged:
I need to normalize it, such that the cells in the first column are unmerged (those should be considered the true "rows"), but such that unmerged groups of cells (in these "rows") are put into a single cell with newlines to retain the list-like content:
Note that in some columns besides the first, there may also be some merged cells, but in any case the first column should determine what a "row" in the output sheet should look like.
Does such a VBA script exist to do this?
UPDATE: Here's a little pseudo-code for what I was thinking:
foreach row:
determine height of merged cell in column A
unmerge cell in column A (content is in top cell of range?)
for each column after A:
if cell is merged, unmerge (content is in top cell of range?)
else concatenate cell contents with newline separator in top cell of row range
cleanup excess rows from the unmerging
Unfortunately I think there's a bit of complexity in some of these steps.
UPDATE#2: Based on the accepted answer, I created some new code to accomplish my goals:
Sub dlo()
Dim LastRow&, r&, c&, rowheight&, n&, Content$, NewText$
Application.DisplayAlerts = False
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
LastCol = Cells(1, Columns.Count).End(xlToLeft).Column
For r = 1 To LastRow
If Cells(r, 1).MergeCells Then
rowheight = Cells(r, 1).MergeArea.Cells.Count
For c = 1 To LastCol
NewText = vbNullString
For rr = r To (r + rowheight - 1)
Content = Cells(rr, c)
Cells(rr, c) = vbNullString
NewText = NewText & vbCrLf & Content
Next
Cells(r, c).UnMerge
Cells(r, c) = NewText
Next
'Cells(i + 1, 1).Resize(k - 1, 2).Delete Shift:=xlUp
'LastRow = LastRow - rowheight + 1
End If
DoEvents
Next
Application.DisplayAlerts = True
End Sub
The only thing I didn't finish was the deletion of resulting blank rows (I ended up just commenting those out since I knew a could just sort the table to eliminate the blanks).
If anyone has better ideas for how to describe this, please let me know so I can edit the title... I have a feeling this is not a rare need, so I'd like to help other find this.
Is this what you asking for?
Sub dlo()
Dim LastRow&, i&, j&, k&, n&, Content$, Text$
Application.DisplayAlerts = False
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
Do
i = i + 1
Text = vbNullString
If Cells(i, 1).MergeCells Then
k = Cells(i, 1).MergeArea.Cells.Count
n = Cells(i, 1).RowHeight
For j = 1 To k
Content = Cells(j + i - 1, 2)
Cells(j + i - 1, 2) = vbNullString
Text = Text & vbCrLf & Content
Next
Cells(i, 1).UnMerge
Cells(i, 2) = Mid(Text, 3)
Cells(i + 1, 1).Resize(k - 1, 2).Delete Shift:=xlUp
Rows(i).RowHeight = n * k
NewLastRow = LastRow - k + 1
End If
DoEvents
Loop Until i = NewLastRow
Application.DisplayAlerts = True
End Sub
The above code works fine to my dummy data.

vba code not taking correct value of a cell from file

This is my code:
Dim RowLast As Long
Dim sunmLast As Long
Dim tempLast As Long
Dim filterCriteria As String
Dim perporig As Workbook
Dim x As String
tempLast = ThisWorkbook.Sheets("combine BOMs").Cells(Rows.Count, "E").End(xlUp).Row
Range("D5:G" & tempLast).ClearContents
Range("G5:G" & tempLast).Interior.ColorIndex = 0
tempLast = ThisWorkbook.Sheets("combine BOMs").Cells(Rows.Count, "A").End(xlUp).Row
Range("A5:A" & tempLast).ClearContents
tempLast = ThisWorkbook.Sheets("combine BOMs").Cells(Rows.Count, "B").End(xlUp).Row
'Perpetual
Set perporig = Workbooks.Open("\\Etnfps02\vol1\DATA\Inventory\Daily tracking\perpetual.xlsx", UpdateLinks:=False, ReadOnly:=True)
RowLast = perporig.Sheets("perpetual").Cells(Rows.Count, "A").End(xlUp).Row
perporig.Sheets("perpetual").Cells(3, 1) = "Part Number"
For i = 5 To tempLast
Cells(i, 1) = i - 4
perporig.Sheets("perpetual").AutoFilterMode = False
filterCriteria = ThisWorkbook.Sheets("combine BOMs").Range("B" & i).Value
perporig.Sheets("perpetual").Range("A3:J" & RowLast).AutoFilter Field:=1, Criteria1:=filterCriteria
Counter = perporig.Sheets("perpetual").Cells(RowLast + 1, 1).End(xlUp).Row
If Counter = 3 Then
Cells(i, 5).Value = "Not on perpetual"
Else
ThisWorkbook.Sheets("combine BOMs").Cells(i, 5).Value = WorksheetFunction.Sum(perporig.Sheets("perpetual").Range("H4:H" & RowLast).SpecialCells(xlCellTypeVisible))
x = perporig.Sheets("perpetual").Cells(Cells(RowLast + 1, 1).End(xlUp).Row, 4).Value
MsgBox x, vbOKOnly, perporig.Sheets("perpetual").Cells(RowLast + 1, 1).End(xlUp).Row
ThisWorkbook.Sheets("combine BOMs").Cells(i, 4).Value = x
End If
perporig.Sheets("perpetual").AutoFilterMode = False
Next
perporig.Close savechanges:=False
This is the file from which I am clicking my button (or ThisWorkbook)
This is the perpetual file when it is running on the last row of data:
Notice the difference in D9280: it shows stocking type as "P" in the perpetual file, but "B" in my final result, which comes up in cell D12 in ThisWorkbook. To debug, I created a Msgbox prompt for everytime it gets that value for all rows. For every other row, it gives the correct value ("P"), but for this one, msgbox shows "B". The title of the msgbox is the row number, which shows it is taking the correct row whilr getting the value, just that I don't know why it is taking wrong value. I have tried for different data sources, it seems to be coming up with "B" in wrong places every so often.
In the code, just above the line, I have the line to get the on hand quantity, which it does take correctly (I used xltypevisible to paste values for this field, but that is only because I wanted a sum of the results and this was the only way I knew). It's only this stocking type column which shows wrong values randomly.
Any ideas?
Thanks!
1)
Cells(i, 1) = i - 4
as it is written , it refers to perporig.Cells(i, 1)
is this what you want?
2)
perporig.Sheets("perpetual").Range("A3:J" & RowLast).AutoFilter Field:=1, Criteria1:=filterCriteria
would filter from row 3, while you have headers in row 4 and data from row 5 downwards
change it to
perporig.Sheets("perpetual").Range("A4:J" & RowLast).AutoFilter Field:=1, Criteria1:=filterCriteria
3)
what do you think is Counter doing? Not certainly count visible rows only
Credits to findwindow, I found the answer. The .cells(cells()) part didn't have the correct sheet reference for the inner cells():
Instead of
x = perporig.Sheets("perpetual").Cells(Cells(RowLast + 1, 1).End(xlUp).Row, 4).Value
MsgBox x, vbOKOnly, perporig.Sheets("perpetual").Cells(RowLast + 1, 1).End(xlUp).Row
I used this:
With perporig.Sheets("perpetual")
x = .Cells(.Cells(RowLast + 1, 1).End(xlUp).Row, 4).Value
MsgBox x, vbOKOnly, .Cells(RowLast + 1, 1).End(xlUp).Row
End With
And it worked.
Thanks for your help!