Copy and paste data based on text in cell next to it - excel

I want the code to check every cell in in the range “A3:AAA3” for a specific text. If the cell contains that text, I want it to copy the text in the cell on the right, to two rows above (see below for illustration):
The copied text will be a date.
I have already got a piece of code which identifies every column with this text and sets the column width:
Dim c as Range
For Each c In Range("A3:AAA3").Cells
If c.Value = "TEXT" Then
c.EntireColumn.ColumnWidth = 4
End If
Next c
I can use copy and paste if the cell is already selected:
Dim s As Range
Set s = Selection.Cells(1)
s.Offset(0, 1).Copy
s.Offset(-2, 0).PasteSpecial xlPasteAll
And I feel like I should be able to combine the two into something like the below so that it selects the cell with the text, and copies and pastes the cell next to it, and then loops onto the next one (something like below?), but all my attempts aren’t working – it’s not coming up with an error message, just not doing anything.
Dim c As Range
For Each c In Range("A3:AAA3").Cells
If c.Value = "TEXT" Then
c.Select
c.Offset(0, 1).Copy
c.Offset(-2, 0).PasteSpecial xlPasteAll
End If
Next c
Thoughts? I’m sure it’s a very simple solution but I’m a bit stuck.

The c.Value = "TEXT" will check if the value is exactly TEXT but in your example it is 1 TEXT so it is only like TEXT. So we need to use a place holder and the like operator.
Dim c As Range
For Each c In Range("A3:AAA3").Cells
If c.Value Like "*TEXT*" Then
c.Offset(0, 1).Copy Destination:=c.Offset(-2, 0)
End If
Next c
Note that you can copy/paste in one line.
And you don't need c.Select (see How to avoid using Select in Excel VBA.)
Note that Excel does not know in which worksheet this range is Range("A3:AAA3").Cells better specify the worksheet like ThisWorkbook.Worksheets("MySheet").Range("A3:AAA3").Cells
Finally in all cases it is helpful if you debug your code step by step using F8 so you can see what your code does in every step and investigate the values of your variables to see where exactly it goes wrong.
Off Topic:
I would even prefer the following style:
c.Offset(ColumnOffset:=1).Copy Destination:=c.Offset(RowOffset:=-2)
which reads more intuitive.

Related

Pasting Values as Displayed

I have a column of cells in excel that have the following formatting: "0000.00"
FYI, the quotes are not part of formatting.
Basically, four digits followed by two decimals. However, when the numbers are like "600", they need to be displayed as "0600.00". However, the list of numbers provided to me are displayed that way through formatting, so if I am trying to VLOOKUP, it can't process it; it sees "600", not "0600.00" that is displayed to me.
I am aware of PasteSpecial Paste:=xlPasteValues, but this pastes "600", not the "0600.00" that is displayed to me. Currently I can achieve such results by copying the values and pasting them into notepad —which suggests to me there is a way to do this— but I'd like to create a macro to do this for me.
Sorry for any redundant explanation, just wanted to avoid getting answers relating to pasting values only, which is not what I am looking for.
As you said, to use VLOOKUP with formatted text as the lookup value, you'll need the value of the cell to match with the value of the lookup value, so you'll have to convert the value in the cell to text with something like this (example for a single cell):
Dim rng As Range
Set rng = Range("A1")
rng.PasteSpecial xlPasteFormulasAndNumberFormats
Dim TextValue As String
TextValue = Format(rng, rng.NumberFormat)
rng.NumberFormat = "#" 'We need this line to turn the cell content into text
rng.Value2 = TextValue
I'm pretty sure no PasteSpecial options will allow you to do what you want in a single operation, so this solution is a workaround that does it in two steps.
Multiple cells case:
I realize that the code above doesn't address the issue of pasting multiple cells, so here's a procedure that can be used to copy the formatted number as text from one range to another:
Sub CopyAsFormattedText(ByRef SourceRange As Range, ByRef DestinationRange As Range)
'Load values into an array
Dim CellValues() As Variant
CellValues = SourceRange.Value2
'Transform values using number format from source range
Dim i As Long, j As Long
For i = 1 To UBound(CellValues, 1)
For j = 1 To UBound(CellValues, 2)
CellValues(i, j) = Format(CellValues(i, j), SourceRange.Cells(i, j).NumberFormat)
Next j
Next i
'Paste to destination by using the top left cell and resizing the range to be the same size as the source range
Dim TopLeftCell As Range
Set TopLeftCell = DestinationRange.Cells(1, 1)
Dim PasteRange As Range
Set PasteRange = TopLeftCell.Resize(UBound(CellValues, 1), UBound(CellValues, 2))
PasteRange.NumberFormat = "#" 'We need this line to turn the cells content into text
PasteRange.Value2 = CellValues
End Sub
It's basically the same idea, but with a loop.
Note that if the formatting is always the same, you could make it a variable and apply it to every values in the array instead of calling .NumberFormat on every cell which inevitably adds a little bit of overhead.
Sidenote
One could ask why I'm not suggesting to use :
SourceRange.Cells(i, j).Text
instead of
Format(CellValues(i, j), SourceRange.Cells(i, j).NumberFormat)
And that would be a very good question! I guess, the fact that .Text can return "###..." when the column isn't sized properly always makes me afraid of using it, but it certainly would look much cleaner in the code. However, I'm not sure what would be better in terms of performance. (Relevant article by Charles Williams)

Return cells content from range

Yesterday I learned here how to copy a row to a second sheet.
Sub maJolieProcedure(Texte As String)
With Worksheets("employes").Range("A:A")
Set c = .Find(what:=Texte)
If Not c Is Nothing Then
firstAddress = c.Row
Worksheets("employes").Rows(firstAddress).Copy _
Destination:=Worksheets("rapport").Range("A1")
MsgBox "Ok"
Else
MsgBox "Nok"
End If
End With
End Sub
To respect the formatting of the second sheet, I want to copy and paste the contents of each cell one by one.
I can identify the line number. However, I can't figure out how the Range object can return each cell one by one. For example, C3 content if Rows = 3.
Thanks a lot.
If you don't want to paste the formatting from one range to another paste values only.
Worksheets("employes").Rows(firstAddress).Copy
Worksheets("rapport").Range("A1").PasteSpecial xlValues
That's the same for all ranges, whether 1 cell or a million. The Copy process copies the subject to memory as one block. Any parsing must be done before the Copy instruction. An alternative is to read a range into an array.
Dim Arr As Variant
Arr = Worksheets("employes").Rows(firstAddress).Value
This will create a 3D array of 1 row and about 16000 columns. You might decide to limit your enthusiasm to only what you need.
With Worksheets("employees")
Arr = .Range(.Cells(firstAddress, 1), .Cells(firstAddress, .Columns.Count).End)xlToLeft)).Value
End With
Pay attention to the leading periods within the With statement. Each such period stands for the object mentioned in the With statement.
If your goal is to respect the formating of the second sheet, you don't need to loose time copying cell by cell.
It is more effective to do a paste special, like you do with the mouse:
Range("A1").Copy
Range("B1").PasteSpecial Paste:=xlPasteValues
works very well also with bigger ranges if you need:
Range("A1:A12").Copy
Range("B1:B12").PasteSpecial Paste:=xlPasteValues
or even
Range("A1:A12").Copy
Range("D3").PasteSpecial Paste:=xlPasteValues
If your goal is to really access all cell of a range individually , you just iterate on the range. For example:
For Each cell In Range("A1:A12")
cell.Value = cell.Value + 2
Next cell

Selecting a range using Cells function in vba

I want to select I15:R15 and I20:R20 using Cells() function in vba. Can't use Range as the row number will always be different.
In first go, I want to copy and pasteI15:R15 and I16:R16 into a sheet.
In next go, I want to copy and paste I15:R15 and I17:R17 , In next go, I want to copy and paste I15:R15 and I18:R18 ..... and so on.
If I use Range() function, then I don't know whether it will always be Copying I15:R15 or I15:S15 or so on, basically I15 is fixed, the right side of range (i.e., column whether R or S or T is not decided.
After reading your updated post, you are looking for something like the code below:
Dim Rng As Range
Dim i As Long
For i = 16 To 20
' Set a dynamic range of "I15:R15" and another row, starting from row 16 and incrementing untill 20
Set Rng = Application.Union(Range(Cells(15, "I"), Cells(15, "R")), Range(Cells(i, "I"), Cells(i, "R")))
Rng.Copy
' do your Paste code here
Set Rng = Nothing
Next i

excel vba select multiple columns in a loop

Edit: I only have 28,000 columns, and you all are correct that they can't all fit in one worksheet. I was testing my code with only a portion of the data and hadn't yet realized that it will not all fit
I have 28,000 columns of data. I am trying to to copy specific columns 5,12,19,26...(ie for i=1:4000, column number = 7*(i-1) + 5). My original thought is below, but the problem is that after each iteration of the loop, the previous column is deselected. So the code below does not copy the intended data.
For i = 1 To 4000
DataSheet.Columns(7 * (i - 1) + 5).Select
Next i
Selection.Copy
ResultsSheet.Paste
I thought about the alternative below (which works, but very slowly), but I was hoping I could write something that executes more quickly (part of the problem is the code selects the destination sheet and pastes each column individually, essentially quadrupling the number of steps as something similar to the first solution).
For i = 1 To nSymbols
DataSheet.Columns(7 * (i - 1) + 5).Copy
ResultsSheet.Select
Columns(i+1).Select
ActiveSheet.Paste
Next i
Any ideas on how to make this code run (faster)?
Use Union and increment your For ... Next by 7 for each increment.
dim c as long, rng as range
with worksheets("sheet1")
set rng = intersect(.columns(5), .usedrange)
for c = 12 to 4000 step 7
set rng = UNION(rng, intersect(.columns(c), .usedrange))
next c
end with
debug.print rng.address(0, 0)
rng.copy destination:=ResultsSheet.cells(2, 1)
I've added Intersect with UsedRange to reduce the full column references. Due to the Union'ed range, this Copy & Paste resjults in a Copy, Paste Special, Values and fORMATS.

VBA User Form - Need it to copy formula from column F, 1 row above

I have a form I made for users to enter data. The data get's inserted into the next available row. That works well, but now I need the formula from the cell above in Column F to be copied into the new cell. Is there a code I could use this to work along with the copying of the input values to the sheet?
Any help with this would be greatly appreciated.
Edit: Method 2 is probably better suited for your purpose as it will adapt the cell references in the previous line to the next line.
Method 1: To set the formula of a cell, use
Sheets("sheet name").cells(row, column).Formula = ....
Row and column must be specified as integer values, I.e. For column F it would be 6. Assuming you have the number of the next free line in a variable called NextFreeLine:
Sheets("sheet name").cells(NextFreeLine, 6).Formula = Sheets("sheet name").cells(NextFreeLine-1, 6).Formula
Method 2: If you insist on literally copying the formula from somewhere else, try this (this will adapt the cell references of the formula for the previous line to the next one-- just like copy/pasting it using Ctrl-C, Ctrl-V):
Sheets("sheet name").cells(NextFreeLine-1, 6).Copy
Sheets("sheet name").cells(NextFreeLine, 6).PasteSpecial Paste:=xlPasteFormulas
The method you are using to put into 'the next available row' would have been nice to see but perhaps you can translate this for your own purposes.
'put the newval into the next available cell in column A
cells(rows.count, 1).end(xlup).offset(1, 0) = newval
'copy the formula in column F to the new row
cells(rows.count, 1).end(xlup).offset(-1, 5).resize(2, 1).filldown
Your value goes into the next available row based on column A. The same column is used in much the same manner but offset up a row and resized to two rows in height before executing the fill down command.

Resources