I code to fill down values. This is straight forward and can be done even without a script. (special - blanks - =value - ctrl entr)
I have another column where I need to copy the data upwards.
As seen in the image below, column A is filled downwards using the code;
Sub FillDown()
With Range("A:A")
.SpecialCells(xlCellTypeBlanks).FormulaR1C1 = "=R[-1]C"
.Value = .Value
End With
End Sub
Operations Period is column A. Occurences are column Q. They are not all 1s. There are mixed values.
Column Q has the data which needs to be filled upward.
Adapted for going backwards. Not sure there is a cleverer way to do this. Over my head if there is.
Sub FillDown()
Dim r As Range
For Each r In Range("A:A").SpecialCells(xlCellTypeBlanks).Areas
r.Value = r.Offset(r.Rows.Count).Resize(1).Value
Next r
End Sub
Before
After
Related
I need some help with simple vba macro.
I've got this sheet with 3 rows A, H, I
Cells in A are filled with some values and colored.
Cells in H may be filled with similar values and not colored.
Cells in I contain some numeric data.
Overall idea for macro is to match values from A and H, if H has exact value from A, then it's filled with the A cell color. This part is working fine for me.
Next step is to color cells in I accordingly to H, just based on it's position relative to H. For example I54 must be colored same as H54.
I tried adding another for cycle for I row, and plain range("I3:I100").interior.color = range("H3:H100").interior.color but it seems I don't quite understand vba or programming...
Here's my current script
Sub test()
Dim acel As Range
Dim hcel As Range
With Worksheets("Sheet1")
For Each acel In .Range("A3", .Cells(.Rows.Count, "A").End(xlUp))
For Each hcel In .Range("H3", .Cells(.Rows.Count, "H").End(xlUp))
If hcel.Value = acel.Value Then
hcel.Interior.Color = acel.Interior.Color
End If
Next hcel
Next acel
End With
End Sub
Try setting the color for each cell, not all cells at once:
For Each acel In .Range("H3:H100")
acel.Offset(0, 1).Interior.Color = acel.Interior.Color
Next acel
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
I have a bunch of cells that have two lines of text in each cell after pulling the data into Excel.
What I am looking to do is use a macro with the Trim function to remove everything in the cell after the second line.
I'm puzzled with this data, it's as if you were to enter data in a cell and Enter down to the next cell, but it's one cell and is not merged.
ex.
Someone's Name [123]
Procedure room, procedure done
Is there a way to identify this line break?
thanks so much for any assistance, my heads spinning and I'm punching out for the day.
cheers
Just look for the ASCII-10. Select the cells you wish to process and run:
Sub KleanUp()
Dim r As Range
For Each r In Selection
r.Value = Split(r.Value, Chr(10))(0)
Next r
End Sub
Only the first line will be retained in each cell.
EDIT#1:
As Ralph points out, ASCII-13 should also be considered, therefore:
Sub KleanUp2()
Dim r As Range
For Each r In Selection
r.Value = Split(Replace(r.Value, Chr(13), Chr(10)), Chr(10))(0)
Next r
End Sub
This converts to a single-style line-break.
EDIT#2:
It is possible to improve the performance of the sub by:
reading the data into a VBA array as a single large block
looping through the array (in VBA)
transferring the data back to the worksheet in a single block
I have a database containing "N/A" at different cells, caused by temporary system offline.
I used to fill these "N/A"'s using the formula shown with the image:
As you can see, the datum at columns A are cumulative, so are B and C. The "N/A"s are compensated by spreading the difference between the last reading before the first "N/A" and the first reading after the last "N/A"
The "N/A"'s appear at different points and have varying lengths.
Is there maybe a vba code to help me do this in one click for the entire database?
Thank you sirs for your kind help.
You could try running this VBA code to interpolate the N/A values based on numbers above and below:
Sub FillNA()
Dim rng As Range, col As Range, a As Range
Set rng = Cells.SpecialCells(xlCellTypeConstants, xlTextValues)
For Each col In ActiveSheet.UsedRange.Columns
If Not Intersect(rng, col) Is Nothing Then
For Each a In Intersect(rng, col).Areas
If a(1) = "N/A" Then
a(0).Resize(a.Count + 2).DataSeries Trend:=True
End If
Next a
End If
Next col
End Sub
(If N/A appears at the beginning or end of the range you will need to decide how to handle this case and make appropriate adjustments)
So, in Sheet1 I have base of some names and it looks like this:
In Sheet2 I'm working with these names from Sheet1. I'm doing that in a way that I'm entering Code value in column A and in column B I get the Name, in column C I get the Last Name. That looks like this:
I've done this with formulas, entering it in the formula bar. For column A(or Name) I've used this formula: =IFERROR(VLOOKUP(A2;Sheet1!A:C;2;FALSE);"") and for column B(or Last Name) I've used this one: =IFERROR(VLOOKUP(A2;Sheet1!A:C;3;FALSE);""). I've dragged these formulas to row 20 and it works great.
Now, what I'd like to do is to put these formulas into Excel VBA code and them to work for noted range. I've just started to use VBA and I don't know how to do it in it, tried something but doesn't work, ..., I've done this so far. I'm new to this Excel/Macro/VBA thing so any help would be appreciated.
The below code will work if you type in your Code values in sheet2 and highlight them, and run this macro:
Selection.Offset(0, 1).FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-1],Sheet1!C[-1]:C,2,FALSE),"""")"
Selection.Offset(0, 2).FormulaR1C1 = "=IFERROR(VLOOKUP(RC[-2],Sheet1!C[-2]:C,3,FALSE),"""")"
Selection.Offset(0, 1).Value = Selection.Offset(0, 1).Value
Selection.Offset(0, 2).Value = Selection.Offset(0, 2).Value
Edit: If you are wanting to update values as you type use (thank you #PeterAlbert for added optimisation!):
Private Sub Worksheet_Change(ByVal Target As Range)
'end if the user made a change to more than one cell at once?
If Target.Count > 1 Then End
'stop system activating worksheet_change event while changing the sheet
Application.EnableEvents = False
'continue if column 1(A) was updated
'and
'dont continue if header or row 1 was changed
If Target.Column = 1 And Target.Row <> 1 Then
With Target.Offset(0, 1) 'alter the next cell, current column +1 (column B)
'RC1 = current row and column 1(A) e.g. if A2 was edited, RC1 = $B2
'C1:C2 = $A:$B
.FormulaR1C1 = "=IFERROR(VLOOKUP(RC1,Sheet1!C1:C2,2,FALSE),"""")"
.Value = .Value 'store value
End With
With Target.Offset(0, 2) 'alter the next cell, current column +2 (column C)
'C1:C3 = $A:$C
.FormulaR1C1 = "=IFERROR(VLOOKUP(RC1,Sheet1!C1:C3,3,FALSE),"""")"
.Value = .Value 'store value
End With
End If
Application.EnableEvents = True 'reset system events
End Sub
Explinatioin of RC:
The FormulaR1C1 formula types are good to use when referencing a cell with respect to the current cell. There a few rules to remember:
The R stands for Row and C is for Column and the integer after it, if any, defines the row or column;
As a basis the RC formula references itself;
Any number following the R or C wraped in [] is an offset to itself, e.g. if you are in cell A1 and use R[1]C[1] you would be referencing cell B2;
Also any number following the R and C is an exact, e.g. if you reference R2C2 no matter the cell you are in would also point to B2; and
To complicate things if you were in cell C5, e.g. using Range("C5").FormulaR1C1 = and coded the follwing:
"=RC[-1]" references cell B5
"=RC1" references cell A5, more rightly $A5
"=R[1]C[-2]" references cell A6
"=Sum(C[-1]:C5)" is =Sum(B:E), more rightly =Sum(B:$E)
If I understand your question and comments correctly, you want to ensure that columns B&C always show you the right values based on your formula, but also want to protect (and maybe even hide the formula) from the users.
I'd suggest you use sheet protection instead: all you need to do is to unlock the cells you want the users to edit, i.e. select column A and in the _ Format cells_ dialog uncheck "Locked" in the Protection tab. Similarly for columns B&C, check "Hidden". Now right click the sheet name and select Protect Sheet. Once this is done, the user can edit column A - but will not see the formula in B&C and cannot edit those cells.
If for some reasons you need to ensure this in VBA, use the following code:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False 'to prevent endless loop
With Target.Offset(, 2 - Target.Column).Resize(, 2)
.FormulaR1C1 = "=IFERROR(VLOOKUP(RC1,Sheet1!C1:C3,COLUMN(RC),0),"""")"
.Value = .Value
End With
Application.EnableEvents = True
End Sub
You need to place this in the module of the worksheet.