I'm looping through workbooks to aggregate the data to one sheet. The data on the various source sheets is always in the same columns but the rows will vary.
I'm assigning values but conditional formatting is coming through.
Screen updating is off.
How can I copy values from one book to another?
For Each sheet In Workbooks(filename).Worksheets
If sheet.Name = "Template" Then
lastrow = sheet.Range("A" & Rows.Count).End(xlUp).row
For row = 2 To lastrow
All.Range("A" & All_nextrow).Value = sheet.Range("A" & row).Value
All.Range("B" & All_nextrow).Value = sheet.Range("B" & row).Value
All.Range("C" & All_nextrow).Value = sheet.Range("C" & row).Value
All.Range("D" & All_nextrow).Value = sheet.Range("D" & row).Value
All.Range("E" & All_nextrow).Value = sheet.Range("E" & row).Value
All.Range("F" & All_nextrow).Value = sheet.Range("F" & row).Value
All.Range("G" & All_nextrow).Value = sheet.Range("G" & row).Value
All.Range("H" & All_nextrow).Value = sheet.Range("H" & row).Value
All.Range("I" & All_nextrow).Value = sheet.Range("I" & row).Value
All.Range("J" & All_nextrow).Value = sheet.Range("J" & row).Value
All.Range("K" & All_nextrow).Value = sheet.Range("K" & row).Value
All.Range("L" & All_nextrow).Value = Workbooks(filename).Name
All_nextrow = All_nextrow + 1
Next row
End If
Next sheet
This might be what you are looking for. There are some issues with your code you need to know.
In this example, I'm using "All" as the name of the sheet you are putting this onto.
This code uses a simple loop to go through the columns, where you were using Range and the actual letter name of the column, this uses Cells(lRow, lCol) and loops that way, until you get to column L where you change the pattern.
I also removed the for each worksheet, because you are running an IF statement making ONLY "TEMPLATE" the one that will be used. So there is no need to loop through all of them to find the one you know you want. If you meant to use more than that, the If Sheet.Name = "Template" needs to go.
Give this code a shot, and modify it to your needs. I will be happy to modify the answer if you comment with any glitches.
Sub DataAggregate()
Dim sheet As String
Dim all As String
Dim allRow As Long
all = "All" 'whatever the name of "ALL" is, set here.
allRow = 2
sheet = "Template"
lastRow = Sheets(sheet).Range("A" & Rows.Count).End(xlUp).row
For lRow = 2 To lastRow
For lCol = 1 To 11
Sheets(all).Cells(allRow,lCol) = Sheets(sheet).Cells(lRow, lCol).Text
Next lCol
Sheets(all).Cells(allRow, "L") = sheet 'or filename' 'confused as to what you want
allRow = allRow + 1
Next lRow
Next ws
End Sub
I'm not sure of understanding what you need but if you want to copy all the cells between A2 and L{lastrow} you can use:
lastrow = SheetFrom.Range("A" & Rows.Count).End(xlUp).Row
SheetFrom.Range("A2:L" & lastrow).Copy
SheetTo.Range("A2").PasteSpecial (xlPasteValues)
Sub CopyPaste()
Dim WorkbookToCopy As Workbook
Dim WorkbookToPaste As Workbook
Dim RowCount As Integer
Set WorkbookToCopy = Workbook1 'Workbook to copy name like Workbook1
Set WorkbookToPaste = Workbook2
RowCount = 1 ' 'clean' row in WorkbookToPaste
For Each Sheet In Workbook1
For Each Column In Sheet
RowCount = 1
For Each Cell In Column
WorkbookToPaste.Sheets(Sheet).Cells(RowCount, Column).Value = Cell.Value
RowCount = RowCount + 1
Next
Next
Next
End Sub
I'm not sure that its work, but I would like to show you some logic, which you can use in your macro.
For anybody still looking for a good answer, the cells format can be controlled with use of 'NumberFormat' in conjunction with .FormulaR1C1.
When any value stored in a cell with ".value" it internally formatted. To override this you need to alter the NumberFormat and use '.FormulaR1C1' instead of '.value'.
All.Range("A" & All_nextrow & ":" & "L" & All_nextrow).NumberFormat = "#"
Then
All.Range("A" & All_nextrow).FormulaR1C1 = sheet.Range("A" & row).Value
You can achieve this by .copy and .PasteSpecial as suggested by #genespos but I'm not a fan of cell interactions during a macro execution.
Related
Hi I made a macro that creates different workbooks I'm trying to use it in a loop but the range changes to the open workbook and when I try to use the complete path to my workbook the variable in which I store the range marks "Nothing".
row = ActiveCell.row
Dim cell As Range
Dim quote As Integer
quotesToDo = Selection.Rows.Count
For quote = 1 To quotesToDo
cell = Workbooks("PLANTILLA FORECAST 2019.xlsm").Worksheets("CONTROL DE LEADS").Range("D" & row)
If cell.EntireRow.Hidden = False Then
row = cell.row
name = Range("D" & row).Value
location = Range("G" & row).Value
mail = Range("H" & row).Value
phone = Range("I" & row).Value
wantedProduct = Range("J" & row).Value
Call Query2(exchange, name, location, mail, phone, generalAddress, row)
End If
row = row + 1
Next quote
Please use set for Range object.
I'm copying rows of data from one spreadsheet to another on a button press when cell I says "Yes" and deleting the original row of data. I have multiple ranges I'm copying from the same row, because the second spreadsheet doesn't need all the data held in the first. (first spreadsheet has over 20 columns worth of data but the second has half that). Is there an easy way to make sure this all gets copied to the same row in the new spreadsheet?
Basically what I'm currently doing is copying each of the ranges to the corresponding column in the new spreadsheet with the row number set to being the last used row offset by 1. Which works fine if the previous cells actually have data in, but sometimes they don't (the data is on households and some have more data than others so not all columns are always filled) so the data is placed in a different row from the rest of my data for that particular household.
Private Sub CommandButton1_Click()
Dim c As Range
Dim r As Integer
Dim LastRowD
Dim LastRowR
Dim Database As Worksheet
Dim DeReg As Worksheet
'Set worksheet deignation as needed
Set Database = ActiveWorkbook.Worksheets("Fostering Households")
Set DeReg = ActiveWorkbook.Worksheets("De-Registrations")
LastRowD = Database.Cells(Database.Rows.Count, "A").End(xlUp).Row
'Searches all rows in I
For Each c In Database.Range("I1:I" & LastRowD)
'Catches cases where "Yes" is present in column I
If c = "Yes" Then
LastRowR = Database.Cells(Database.Rows.Count, "A").End(xlUp).Offset(1, 0)
r = c.Row
'Copies the desired column data from rows containing "Yes" from Database tab and pastes it in DeReg tab
Database.Range("A" & r & ":G" & r).Copy DeReg.Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
Database.Range("H" & r).Copy DeReg.Range("AJ" & Rows.Count).End(xlUp).Offset(1, 0)
Database.Range("J" & r & ":X" & r).Copy DeReg.Range("H" & Rows.Count).End(xlUp).Offset(1, 0)
Database.Range("AN" & r).Copy DeReg.Range("W" & Rows.Count).End(xlUp).Offset(1, 0)
Database.Range("AS" & r).Copy DeReg.Range("X" & Rows.Count).End(xlUp).Offset(1, 0)
Database.Range("AZ" & r & ":BH" & r).Copy DeReg.Range("Y" & Rows.Count).End(xlUp).Offset(1, 0)
End If
Next c
For i = 250 To 1 Step -1
If Database.Range("I" & i) = "Yes" Then
Database.Rows(i).EntireRow.Delete
End If
Next i
End Sub
I've tried defining the last row based on whether "A" has data in (this is the only cell that is always used) with the code:
LastRowR = Database.Cells(Database.Rows.Count, "A").End(xlUp).Offset(1, 0) and then replacing my copy past code with:
Database.Range("A" & r & ":G" & r).Copy DeReg.Range("A" & LastRowR & ":B" & LastRowR).Row
But this didn't work at all - it copied the first row it found with "Yes" in infinitely and overwrote all the data already present.
I also tried:
Database.Range("A" & r & ":G" & r).Copy DeReg.Range("A" & LastRowR).PasteSpecial
which also came with a world of problems and errors.
What I want is to search for the last used Row based on what's in column A, offset by 1, and then past the data in the column I designate, rather than the last row used being defined by the column I'm trying to paste in - is this even doable? I can't seem to find any information on this particular issue.
Also, if there is a better way of handing multiple ranges that would be great as it seems rather convoluted currently!
DeReg.Range("A" & Rows.Count).End(xlUp).Offset(1, 0) evaluates to:
DeReg.Range("A" & ActiveSheet.Rows.Count).End(xlUp).Offset(1, 0), so unless DeReg is the activesheet, you will get the wrong range.
See if this helps:
.... other code
'LastRowR = Database.Cells(Database.Rows.Count, "A").End(xlUp).Offset(1, 0)
r = c.Row
'Copies the desired column data from rows containing "Yes" from Database tab and pastes it in DeReg tab
With Database
LastRowR = DeReg.Range("A" & DeReg.Rows.Count).End(xlUp).Row + 1
.Range("A" & r & ":G" & r).Copy DeReg.Range("A" & LastRowR)
.Range("H" & r).Copy DeReg.Range("AJ" & LastRowR)
.Range("J" & r & ":X" & r).Copy DeReg.Range("H" & LastRowR)
.Range("AN" & r).Copy DeReg.Range("W" & LastRowR)
.Range("AS" & r).Copy DeReg.Range("X" & LastRowR)
.Range("AZ" & r & ":BH" & r).Copy DeReg.Range("Y" & LastRowR)
End With
End If
... other code
Some helpful tips:
i is not declared. Declare as Long.
LastRowR, r & LastRowD should be declared as Long.
Replace ActiveWorkbook with ThisWorkbook.
The copy paste method used may slow down the program, because this method copies and pastes both values and formatting.
When you want to paste in the line after last row, use +1 (Example: LastRow = sht.Cells(sht.Rows.Count, "A").End(xlUp).Row +1
Just a couple thoughts. Firstly, you have declared multiple things that are unnecessary (IMO). I have adjusted your for loop to simply loop through a value that then references the range you want. This way you can use the i value a lot more efficiently than first setting a range and then looping through and referencing the row etc.
Additionally, based on the understanding I get from your post, if you use the .UsedRanged method your outputs will start at the last row on the new sheet, irregardless of your previously chosen method by column. I have not tested the below code, but it should guide you in a clearer way.
Option Explicit
Private Sub CommandButton1_Click()
Dim i As Long
Dim LastRowD As Long
Dim LastRowR As Long
Dim Database As Worksheet
Dim DeReg As Worksheet
'Set worksheet deignation as needed
Set Database = ActiveWorkbook.Worksheets("Fostering Households")
Set DeReg = ActiveWorkbook.Worksheets("De-Registrations")
LastRowD = Database.Cells(Database.Rows.Count, "A").End(xlUp).Row
'Searches all rows in I
For i = 1 To LastRowD
'Catches cases where "Yes" is present in column I
If Database.Range("I" & i) = "Yes" Then
LastRowR = Database.UsedRange.Rows.Count + 1
'Copies the desired column data from rows containing "Yes" from Database tab and pastes it in DeReg tab
Database.Range("A" & i & ":G" & i).Copy DeReg.Range("A" & LastRowR)
Database.Range("H" & i).Copy DeReg.Range("AJ" & LastRowR)
Database.Range("J" & i & ":X" & i).Copy DeReg.Range("H" & LastRowR)
Database.Range("AN" & i).Copy DeReg.Range("W" & LastRowR)
Database.Range("AS" & i).Copy DeReg.Range("X" & LastRowR)
Database.Range("AZ" & i & ":BH" & i).Copy DeReg.Range("Y" & LastRowR)
End If
Next i
For i = 250 To 1 Step -1
If Database.Range("I" & i) = "Yes" Then
Database.Rows(i).EntireRow.Delete
End If
Next i
End Sub
I am trying to replicate in VBA the simple function in excel which allows you to repeat a function through an entire column, and stops when the columns on the side are empty. Specifically, I want to repeat an if - else if function for the entire relevant part of the column
Here's an attempt which does not really work
Sub RepeatIfElseif
Range("A1").Select
If selection > 0 Then
Range("B1").Select
ActiveCell.FormulaR1C1 = "X"
Range("A1").Select
ElseIf selection <= 0 Then
Range("B1").Select
ActiveCell.FormulaR1C1 = "Y"
End If
Range("B1").Select
selection.AutoFill Destination:=Range("B1:B134")
Is there any way I can do it with a loop?
You do not need to loop to drop formulas in. You just need to know where the last row is!
Pick a column that is most likely to represent your last row (I am using Column A in my example) and then you can dynamically drop-down your equation in one line without the loop.
The below will fill in the equation A2 + 1 in Column B starting from 2nd row (assuming you have a header row) down to the last used row in Column A
Option Explicit
Sub Formula_Spill()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1") '<-- Update sheet!
Dim LR As Long
LR = ws.Range("A" & ws.Rows.Count).End(xlUp).Row '<-- Update column!
ws.Range("B2:B" & LR).Formula = "=A2+1" '<-- Update formula!
End Sub
If you want to use a loop, you can use something like the code below:
For i = 1 To 134
If Range("A" & i).Value > 0 Then
Range("B" & i).FormulaR1C1 = "X"
Else
Range("B" & i").FormulaR1C1 = "Y"
End If
Next I
It can be done without a loop, something like:
Range("B1:B134").Formula = "=IF(A1>0," & Chr(34) & "X" & Chr(34) & "," & Chr(34) & "Y" & Chr(34) & ")"
Not sure what formula you are trying to achieve with .FormulaR1C1 = "Y" ?
I'm trying to improve my English, I swear...
I would do something like this:
dim row as long
dim last_row as Long
last_row = ActiveSheet.Range("A1048576").End(xlUp).Row
For row = 1 to last_row
If Range("A" & row).Value > 0 Then
ActiveSheet.Range("B" & row).Value = "X"
Else
ActiveSheet.Range("B" & row).Value = "Y"
End If
Next row
Hope this helps.
I know very little about VBA code, but I can follow along the lines of logic in a given example. So I googled and found a code I edited to highlight duplicates in a worksheet. However, I have a workbook with three sheets. I would like to adapt this to compare sheet 1 and sheet 3, then highlight the duplicates in sheet 1.
Sub Highlight_Dups()
Dim startRow As Integer
startRow = 2
Dim row As Integer
row = startRow
Do While (Range("A" & row).Value <> "")
Dim innerRow As Integer
innerRow = row + 1
Dim StudentID As String
Dim DT As String
Dim Description As String
StudentID = Range("A" & row).Value
DT = Range("H" & row).Value
Description = Range("J" & row).Value
Do While (Range("A" & innerRow).Value <> "")
If (Range("A" & innerRow).Value = StudentID And Range("H" & innerRow).Value = DT And Range("J" & innerRow).Value = Description) Then
Range("X" & row).Value = Range("X" & row).Value & innerRow & ", "
Range("X" & innerRow).Value = Range("X" & innerRow).Value & row & ", "
Rows(row).Interior.ColorIndex = 6
Rows(innerRow).Interior.ColorIndex = 6
End If
innerRow = innerRow + 1
Loop
row = row + 1
Loop
MsgBox "done", vbOKOnly, "done"
End Sub
Any help on how to add ???= Sheets("Sheet1") and ??? = Sheets("Sheet3")
would help me a great deal. Thanks
You might want to consider discarding the laborious task of looping through every cell while comparing it to every other and use a pair of conditional formatting rules.
Option Explicit
Private Sub cfrS1S3dupes()
With ThisWorkbook.Worksheets("sheet1")
With .Range(.Cells(2, "A"), .Cells(.Cells(.Rows.Count, "A").End(xlUp).Row, "J"))
'get rid of pre-existing cfrs
.FormatConditions.Delete
'if duplicate in sheet1 found below row, then fill red
With .FormatConditions.Add(Type:=xlExpression, Formula1:="=countifs($a$2:$a2, $a2, $h$2:$h2, $h2, $j$2:$j2, $j2)>1")
.Interior.Color = 255 'this is the color red
End With
'if duplicate anywhere in sheet3, then fill green
With .FormatConditions.Add(Type:=xlExpression, Formula1:="=countifs(sheet3!$a:$a, $a2, sheet3!$h:$h, $h2, sheet3!$j:$j, $j2)")
.Interior.Color = 5287936 'this is the color green
End With
End With
End With
End Sub
First of all, you should declare 2 sheet objects to make it easier to read and future code maintences easier:
Dim ws1 As Worksheet
Dim ws2 As Worksheet
'use this approach if your sheet's name is dinamic but never changes it's order
'Set ws1 = ThisWorkbook.Sheets(1)
'Set ws2 = ThisWorkbook.Sheets(2)
'use this if name is static
Set ws1 = ThisWorkbook.Sheets("name of worksheet1")
Set ws2 = ThisWorkbook.Sheets("name of worksheet2")
Then just put the Sheets objects in their specific locations like this (pay attention to the 'ws1's and 'ws2's):
Dim StudentID As String
Dim DT As String
Dim Description As String
Do While (ws1.Range("A" & Row).Value <> "")
innerRow = Row + 1
StudentID = ws1.Range("A" & Row).Value
DT = ws1.Range("H" & Row).Value
Description = ws1.Range("J" & Row).Value
Do While (ws2.Range("A" & innerRow).Value <> "")
If (ws2.Range("A" & innerRow).Value = StudentID And ws2.Range("H" & innerRow).Value = DT And ws2.Range("J" & innerRow).Value = Description) Then
'not sure what you are trying to do with this 3 lines, change it for your own needs
ws1.Range("X" & Row).Value = ws2.Range("X" & Row).Value & innerRow & ", "
ws1.Range("X" & innerRow).Value = ws2.Range("X" & innerRow).Value & Row & ", "
ws1.Rows(Row).Interior.ColorIndex = 6
ws1.Rows(innerRow).Interior.ColorIndex = 6
End If
innerRow = innerRow + 1
Loop
Row = Row + 1
Loop
End Sub
ps: i couldn't test it since you didn't provide the base of yours. But since you said you can read code and understand it's logic, I think you'll be fine :)
I would like to write perfectly working code but am faced with this issue. I want to transfer the data as values to another sheet. To fill out the data I use a form with formulas inside cells.
Then every time I click to transfer the data to another sheet it replaces the source data with its values in both sheets, but for me need that forms cells in the sheet1 stay unchanged. I use a form with formula to put data in the sheet1 from different sources, so it should work every time then I use it (now, after each click I have to recover formulas in the sheet1).
Here is the code:
Sub Button4_Click()
Dim x As Long
Dim erow as Long
'Calculate starting rows
x = 15
With Worksheets("Sheet2")
erow = .Cells(.Rows.Count, 1).End(xlUp).Offset(1, 0).Row
End With
With Worksheets("Sheet1")
Do While .Cells(x, 1) <> ""
'Current code replaces the source data with its values'
.Range("A" & x & ":Y" & x).Value = .Range("A" & x & ":Y" & x).Value
'The next line copies values to Sheet2
Worksheets("Sheet2").Range("A" & erow & ":Y" & erow).Value = .Range("A" & x & ":Y" & x).Value
'increment row counters
x = x + 1
erow = erow + 1
Loop
End With
End Sub
You can't write to a cell's .Formula and then add unrelated data to the same cell's .Value - writing to .Value deletes the formula.
So the following code line:
.Range("A" & x & ":Y" & x).Value = .Range("A" & x & ":Y" & x).Value
is unnecessary (and damaging).