How to combine text of multiple cells for instance translate this excel formula to VBA code
Cell F3 should =Q3&"_"&A3&"_"&D3&"_"&(ROUND(M3/1000,1))&"k"
But I would Like it to repeat in every instant so in F99= Q99&"_"&A99&"_"&D99&"_"&(ROUND(M99/1000,1))&"k"
Using VBA Code:
For Each Cel In Range("A1:A100")
If Cel.Value <> "" Then Cel.Offset(0, 5).Value = *Excel Formula NEED* "Q3&"_"&A3&"_"&D3&"_"&(ROUND(M3/1000,1))&"k""*
Saying that if value in column A insert text in same row Column E
I also think that a formula (adapted a little to return "" in case of empty cells) would be the best. But, even if you did not answer my question and you want a solution in VBA, please, test the next code:
Sub testConcatenate()
Dim sh As Worksheet, cel As Range, lastRow As Long
Set sh = ActiveSheet 'please use your sheet here
lastRow = sh.Range("A" & Rows.count).End(xlUp).Row
For Each cel In Range("A1:A" & lastRow)
If cel.value <> "" Then
cel.Offset(0, 5).value = Range("Q" & cel.Row).value & "_" & cel.value & "_" & _
Range("D" & cel.Row).value & "_" & Round(Range("M" & cel.Row).value / 1000, 1) & "k"
End If
Next
End Sub
You maybe clarify here the meaning of "" in your formula, what "k" means and what the last character "*" is used for. I did not use it...
Related
I am still working on streamlining our Attendance worksheet and I decided to add a macro for copying the last three rows and pasting them at the end; the only problem is I need the formula in the first two cells to only change their cell references by 1. The code I have so far is
Sub New_Weekly_Row()
Range("A" & Rows.Count).End(xlUp).Offset(-2).Resize(3).EntireRow.Copy
Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(3).EntireRow.PasteSpecial
Range("A" & Rows.Count).End(xlUp).Offset(-2).Resize(2, 1).Select
End Sub
I have been trying to see if there is a way to either lock the references (both cells that would be copied would just be something like =U34 and =W34 respectively) to only increasing by one or subtracting two from the cells that are pasted to.
The closest thing I have found so far is
Dim r As Range, b As Integer
Set r = Range("A" & Rows.Count).End(xlUp).Offset(-2)
b = Val(Right(r.Formula, Len(r.Formula) - 3))
b = b - 2
r.Formula = Range("U" & Columns.Count).End(xlUp) + CStr(b)
Range("A" & Rows.Count).End(xlUp).Offset(-1).Select
But that just enters it as plain text.
This worked a few times, but stopped
Sub Update_Reference()
Dim myCell As Range
Range("A" & Rows.Count).End(xlUp).Offset(-2).Resize(2).Select
For Each myCell In Selection
If myCell.HasFormula Then myCell.Formula = Left(myCell.Formula, _
Len(myCell.Formula) - 1) & 4
Next myCell
End Sub
I don't know if this information helps any, but this will be used in conjunction with this
Sub New_Weekly_Row()
Range("A" & Rows.Count).End(xlUp).Offset(-2).Resize(3).EntireRow.Copy
Range("A" & Rows.Count).End(xlUp).Offset(1).Resize(3).EntireRow.PasteSpecial
Range("U" & Columns.Count).End(xlUp).Offset(1).Resize(1, 2).Merge (Across)
Range("W" & Columns.Count).End(xlUp).Offset(1).Resize(1, 2).Merge (Across)
Range("Y" & Columns.Count).End(xlUp).Offset(1).Resize(1, 2).Merge (Across)
Range("AA" & Columns.Count).End(xlUp).Offset(1).Resize(1, 2).Merge (Across)
Range("U" & Rows.Count).End(xlUp).Resize(1, 8).Copy
Range("U" & Rows.Count).End(xlUp).Resize(1, 8).Offset(1).PasteSpecial
End Sub
my excelsheets look like this:
Then I tried it with the formula:
=SUMIF(B1:B200;B1:B200<>"#NV";B:B)
But it seems wrong. I want to summarize all numbers if is not #NV in each section (11111, 22222). Each numbers 2,3,4,6,9 belongs to the group 11111. I want to determine the sum of all the values which is allocated to the group 11111.
For 11111: Sums over the cell B2:B6, for 22222, sums over B8:B12. That is what I want to do.
Hope you can help me. If it is possible to have a macro, I would be very thankful, if you can share with your ideas.
Thanks
INDIRECT ft. ARRAY FORMULA
It is highly advised that you replace the occurrences of $B:$B with the actual ranges e.g. $B$1:$B$100
The following two formulas are to be copied to C1 and D1. The second is an array formula and you have to use CTRL+SHIFT+ENTER if you don't have 365.
It's a terrible solution, because the first formula uses indirect which is a volatile (updating after every calculation) function and the second is an array formula. The second should be put in the first instead of D1 but it doesn't work (I'm using Excel 2019). So you have to use an extra column for it. Maybe 365 could accept it.
Hopefully someone will use this information to create a more efficient solution.
The Formulas
These two are the ones you need in C1 and D1:
=IF($B2<>"#NV","",SUM(INDIRECT(ADDRESS(D1,2,4)&":"&ADDRESS(ROW(),2,4))))
=IF($B2<>"#NV","",SMALL(IF($B:$B="#NV",ROW($B:$B)-ROW(INDEX($B:$B,1,1))+2),COUNTIF($B$1:$B1,"#NV")))
This one counts the number of occurrences of "#NV" from B$1 to the current row.
=COUNTIF(B$1:B6,"#NV")
This one is an array formula and returns the row after the first occurrence of "#NV". Note the +2 instead of +1 is for the row below, and the 1 after it represents the first occurrence.
=IFERROR(SMALL(IF($B:$B="#NV",ROW($B:$B)-ROW(INDEX($B:$B,1,1))+2),1),"")
Similarly to the previous, this one is an array formula and returns the row after the last occurrence of "#NV".
=IFERROR(SMALL(IF($B:$B="#NV",ROW($B:$B)-ROW(INDEX($B:$B,1,1))+2),COUNTIF(B$1:B6,"#NV")),"")
This is the SUM/INDIRECT formula: Note the first number 2 is the number to be replaced by the array formula, and the 6 is to be replaced by the last ROW formula.
=SUM(INDIRECT(ADDRESS(2,2,4)&":"&ADDRESS(6,2,4)))
The ROW formula.
=ROW()
Try the next VBA code, please. It creates a range from the error cells of B:B filled column range and exploit the discontinuous range Areas addresses. You did not answer my question regarding the possibility to have two consecutive such errors. Anyhow, the following code is able to deal with such situations, too. If no possible consecutive error rows, the code can be simplified:
Sub testErrorRng()
Dim sh As Worksheet, rngErr As Range, lastRow As Long, Ar As Range
Dim startSum As String, endSum As String, i As Long
Set sh = ActiveSheet
lastRow = sh.Range("B" & rows.count).End(xlUp).row
Set rngErr = sh.Range("B1:B" & lastRow).SpecialCells(xlFormulas)
For Each Ar In rngErr.Areas
i = i + 1
If i = 1 Then
If Ar.cells.count = 1 Then
If Ar.Address = "$B$1" Then
startSum = Ar.Offset(1).Address
Else
Ar.Offset(-1, 1).Formula = "=Sum(B1:" & Ar.Offset(-1).Address & ")"
startSum = Ar.Offset(1).Address
End If
Else
startSum = Ar.cells(Ar.cells.count + 1).Address
End If
Else
If Ar.cells.count = 1 Then
endSum = Ar.Offset(-1).Address
Ar.Offset(-1, 1).Formula = "=Sum(" & startSum & ":" & endSum & ")"
startSum = Ar.Offset(1).Address
Else
endSum = Ar.cells(1).Offset(-1).Address
Ar.cells(1).Offset(-1, 1).Formula = "=Sum(" & startSum & ":" & endSum & ")"
startSum = Ar.cells(Ar.cells.count + 1).Address
End If
End If
Next
If rngErr.Areas(rngErr.Areas.count).row < lastRow Then
endSum = sh.Range("B" & lastRow).Address
sh.Range("C" & lastRow).Formula = "=Sum(" & startSum & ":" & endSum & ")"
End If
End Sub
Please, test it and send some feedback.
Edited:
Shorter version for no consecutive error rows:
Sub testErrorRngSimple()
Dim sh As Worksheet, rngErr As Range, lastRow As Long, Ar As Range
Dim startSum As String, endSum As String, i As Long
Set sh = ActiveSheet
lastRow = sh.Range("B" & rows.count).End(xlUp).row
Set rngErr = sh.Range("B1:B" & lastRow).SpecialCells(xlFormulas)
For Each Ar In rngErr.Areas
i = i + 1
If i = 1 Then
If Ar.Address = "$B$1" Then
startSum = Ar.Offset(1).Address
Else
Ar.Offset(-1, 1).Formula = "=Sum(B1:" & Ar.Offset(-1).Address & ")"
startSum = Ar.Offset(1).Address
End If
Else
endSum = Ar.Offset(-1).Address
Ar.Offset(-1, 1).Formula = "=Sum(" & startSum & ":" & endSum & ")"
startSum = Ar.Offset(1).Address
End If
Next
If rngErr.Areas(rngErr.Areas.count).row < lastRow Then
endSum = sh.Range("B" & lastRow).Address
sh.Range("C" & lastRow).Formula = "=Sum(" & startSum & ":" & endSum & ")"
End If
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.
Goal: Populate F and G columns with proper formulas depending on total PROD-TIME for a block
This is another issue that has come up after one of my previous questions:
How to loop through "blocks" of rows in excel dataset instead of each row individually (VBA)?
I have been able to loop through blocks of rows and can now get the sum of the PROD-TIME for that particular block. This sum is necessary to determine which formula needs to be used in the F and G columns.
This is best illustrated in this workbook,
https://www.dropbox.com/s/vgnqi00h8xosja3/wip%20Gantt%20Template.xlsx?dl=0 , where I have shown how I want the formulas to end up in the F and G columns. But for some reason when I run the macro, it just completely breaks. Some of the formulas don't even use reference cells and use the cell value instead, or reference cells don't even appear. Are the blank F and G columns confusing the macro? How can I make sure that every F and G cell gets filled with something? Errors are fine
Sub getStartEndDate()
Dim WrkSht As Excel.Worksheet
Dim RngColumn As Range, RngBlock As Range
Dim totalHrs As Integer 'total PROD-TIME for the given RngBlock
Dim lastRow As Long
lastRow = ActiveSheet.Cells.SpecialCells(xlCellTypeLastCell).Row
Set WrkSht = ActiveWorkbook.Worksheets(1)
' Populate the last row by itself first since the With-statement below needs to reference rows below current row
Range("E" & lastRow).Formula = "=ROUNDUP(D" & lastRow & "/12,0)"
Range("G" & lastRow).Value = Range("C" & lastRow).Value
Range("F" & lastRow).Formula = "=WORKDAY(G" & lastRow & ", -E" & lastRow & ")"
Columns("F:F").NumberFormat = "yyyy-mm-dd"
With WrkSht
Set RngColumn = .Range("B2:B" & lastRow)
'Starts the first block with the first cell in a column.
Set RngBlock = RngColumn.Cells(1)
'Checks every cell in a column.
For Each rngcell In RngColumn
If rngcell.Offset(0,1).Value <> "" Then
'Checks whether a cell's value equals the cell below it.
If rngcell.Value = rngcell.Offset(1, 0).Value Then
'If equal, includes the cell below in the block.
Set RngBlock = Union(RngBlock, rngcell.Offset(1, 0))
Else
'If not equal, that means the block RngBlock ends
' totalHrs is the sum of the "PROD-TIME" for that particular block
totalHrs = WorksheetFunction.Sum(Range(CStr(Trim(Chr(64 + RngBlock.Column + 2))) _
& CStr(Trim(Str(RngBlock.Row))) & ":" _
& CStr(Trim(Chr(64 + 2 + RngBlock.Column + RngBlock.Columns.Count - 1))) _
& CStr(Trim(Str(RngBlock.Row + RngBlock.Rows.Count - 1)))))
If totalHrs < 12 Then
' If total production time (PROD-TIME) is less than 12 hours, then the start and end date should be the same for all rows in that block
rngcell.Offset(0, 4).Value = rngcell.Offset(0, 1).Value
rngcell.Offset(0, 5).Value = rngcell.Offset(0, 1).Value
Else
' If total production time is greater than 12 hours, then start and end dates are based on a different formula
' e.g. Given row 11, F column formula looks like: =WORKDAY(G11, -E11), G column looks like: =IF(B11=B12,F12,C11)
rngcell.Offset(0, 4).Formula = "=WORKDAY(" & rngcell.Offset(0, 5) & ", -" & rngcell.Offset(0, 3) & ")"
rngcell.Offset(0, 5).Formula = "=IF(" & rngcell & "=" & rngcell.Offset(1, 0) & "," & rngcell.Offset(1, 4) & "," & rngcell.Offset(0, 1) & ")"
End If
'Starts the next block with the cell below.
Set RngBlock = rngcell.Offset(1, 0)
End If
End If
Next rngcell
End With
End Sub
I need some help to understand and modify some code I found in this answer:
Sub Main()
Dim cell As Range
Dim nextRow As Long
For Each cell In Range("K50:K200")
If StrComp(cell, "Late", vbTextCompare) = 0 Then
nextRow = Range("J" & Rows.Count).End(xlUp).Row + 1
Range("J" & nextRow) = Range("B" & cell.Row)
Range("K" & nextRow) = Range("C" & cell.Row)
Range("N" & nextRow) = Range("G" & cell.Row)
Range("O" & nextRow) = Range("H" & cell.Row)
End If
Next
End Sub
What I'd like is:
If late is along with some other words, say late submit, copy values in B and paste in J
if row K has progress along with say in progress, copy values in C to K
If sick is with say on sick leave, copy values in G to N
I tried so hard, but I still didn't succeed in modifying this code to suit my needs.
If late is along with some other words, say late submit
In that case, instead of StrComp, use Instr
If Instr(1, cell, "Late", vbTextCompare) > 0 Then
Similarly for the rest.
If you check Excel's help you will notice that Instr returns a Variant (Long) specifying the position of the first occurrence of one string within another.
Syntax
InStr([start, ]string1, string2[, compare])