I'm using Excel to generate numbers from a basic formula that has 2 variables. I have 600 numbers (specifically coordinates), that I need to generate 13 new numbers from each (so I'll need a total of 8400 values/rows for each X & Y). Since the formula will need to change every 14 rows to a new absolute cell, I am having a hard time thinking of how to accomplish this in Excel using VBA.
My current thought is this:
Add rows to accommodate for the new values.
Fill down columns C and D with the repeating pattern of values.
Create a loop that runs the formula for 14 rows then repeats, keeping the absolute value based on position (?).
Admittedly, I am not a pro at VBA, so any help on how to accomplish this task is greatly appreciated.
See screen grab of data, below, for an example.
Snippet of Data
I used this code to get 13 new rows for my values.
Sub AddRows()
ScreenUpdating = False
With ActiveSheet
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
Dim AddRows As Integer: AddRows = 13
Dim i As Integer: i = lastRow
Do While i <> 1
Rows(i & ":" & i + AddRows - 1).Insert
i = i - 1
Loop
ScreenUpdating = True
End Sub
Related
Hi I am writing Excel VBA code. I just wanted to do subtraction for this kind of table
But I can't figure out how to do that using VBA. Is the code below correct?
Sub OperationO()
Dim OE As Integer
Dim i As Integer
For i = 3 To Range("F6")
Cells(6, i).Value = Cells(2, i).Value - Cells(4, i)
Next i
End Sub
You should really use formulas for something like this, but if you insists on VBA, here it goes.
Whenever you write code for VBA or any similar languages, read what you are writing, what it should/needs to do, as you read it out loud many times the errors pop up. Think of the comments below as "me reading as I write."
Sub OperationO()
'Initiate a Variable type Integer for number storage
Dim OE as Integer
'Initiate another variable same type to use in the loop
Dim i as Integer
'Start a loop from 3 to 6 (because these are the columns you are working with)
For i = 3 to 6
'Set the value in Column "i" on Row 6 to the value in Row 2 minus Row 4 in the same column
'Now here is the thing, when you subtract a negative number, you are adding it, crazy math rules i know, so if the number is negative, you need to Add instead.
Cells(6, i).Value = (Cells(2, i).Value + Cells(4, i).Value)
'If both cells don't contain a number, this will fail, additional checks may help, like IsNumber
Next i
'Its the end of the Sub and you never used the Variable OE, it was declared for nothing.
End Sub
I've been searching for a way to concatenate my Excel (or any other tool/software handling tables) rows based on common cells. As an example:
I have this tab-stop divided table. Each of the values is in a separate row:
angeb* 12 16 18
zyste* 60 61
zynisch* 12
zyste* 60
abstreit* 70
anflunker* 70
angeb* 70
I want to concatenate the rows in a way that the result would be:
angeb* 12 16 18 70
zyste* 60 61
zynisch* 12
abstreit* 70
anflunker* 70
It does work by doing as proposed in this tutorial, but it only concatenates single cell values into another single cell. I also tried going the path basically proposed by this so question and finally leading me to VLOOKUP (description). But they all concatenate in cells.
Basically pretty simple, I need to merge cells with the same Column 1, but keep the columns, just concatenate beyond. The second row can then be deleted, once it is added to the first one. I tried adapting the above scripts, but I could not make it work in one step, just with then converting comma separated values into cells and copying them to new columns. I am not an expert with VBA, but this seems like a very simple functionality, I might as well be missing something. Any help is greatly appreciated.
I have written and color-coded each part of what I did, but here is the general method:
Sort all data A-Z
Use a CountIf statement to count how many times a particular data row shows up.
Assuming 3 columns of data, find MAX() of MaxRows, multiply (here, 3 columns x 2 Rows maximum observed = 6 data max).
Copy the labels, remove duplicates [Green] so you have a condensed table.
Use IndexMatch equations, coupled with IF and IFERROR statements to re-sort the data. Note the +1 for Columns P-Q)
Problem - you can still get a gap, but it's all in the same rows now!
Here's a quick Youtube video on how I did it.
TSpinde Answer 1
I was a little confused by your question so I only concatenated names that were exactly the same.
So the way my code works is it makes an array of tags and when it runs into one that it already has it looks for the next empty slot in the original row. It then adds the value in and does this until it hits an empty cell in the new row. There's a bit of funny business with decreasing the lastrow value and changing the row it's on, but its necessary for it to move to the correct row of data in the next cycle.
This macro assumes that all possible data entries are side by side, for example there wont be a value in C2 and E2 if D2 is empty.
Sub macro()
Dim LastRow As Long
Dim LastCol As Long
Dim TagArray() As String
Dim count As Long
Dim i As Long
Dim j As Long
Dim PreExisting As Boolean
Dim Targetrow As Long
ReDim TagArray(1 To 1)
LastRow = Worksheets(1).Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
LastCol = Worksheets(1).Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
TagArray(1) = Worksheets(1).Range("A1").Value
For i = 2 To LastRow
PreExisting = False
For j = 1 To UBound(TagArray)
If Worksheets(1).Cells(i, 1) = TagArray(j) Then
PreExisting = True
Targetrow = j
Exit For
End If
Next j
If PreExisting Then
For j = 2 To LastCol
If Not IsEmpty(Worksheets(1).Cells(i, j)) Then
For count = 1 To LastCol
If IsEmpty(Worksheets(1).Cells(Targetrow, count)) Then
Worksheets(1).Cells(Targetrow, count) = Worksheets(1).Cells(i, j)
Exit For
Else
If count = LastCol Then
LastCol = LastCol + 1
Worksheets(1).Cells(Targetrow, LastCol) = Worksheets(1).Cells(i, j).Value
End If
End If
Next count
Else
Exit For
End If
Next j
Worksheets(1).Rows(i).Delete
LastRow = LastRow - 1
i = i - 1
Else
ReDim Preserve TagArray(1 To UBound(TagArray) + 1)
TagArray(UBound(TagArray)) = Worksheets(1).Cells(i, 1)
End If
Next i
End Sub
Hopefully, you find this useful if you wanted to use it in VBA instead of worksheet functions.
I am trying to create a function or functions that can sum daily hours from time cards for each client to come up with the total hours worked per day. Each client has it's own sheet inside of a single workbook.
Currently, I have a function that determines the sheet that goes with the first client (the third sheet in the workbook):
Function FirstSheet()
Application.Volatile
FirstSheet = Sheets(3).Name
End Function
And one to find the last sheet:
Function LastSheet()
Application.Volatile
LastSheet = Sheets(Sheets.Count).Name
End Function
The part that I am having trouble with it getting these to work within the sum function.
=sum(FirstSheet():LastSheet()!A1
That is basically what I want to accomplish. I think the problem is that I don't know how to concatenate it without turning it into a string and it doesn't realize that it is sheet and cell references.
Any help would be greatly appreciated.
So, an example formula would look like this:
=SUM(Sheet2!A1:A5,Sheet3!A1:A5,Sheet4!A1:A5)
That would sum Sheet2-Sheet4, A1:A5 on all sheets.
Is there a reason you need to write the VBA code to do this?
Can't you just enter it as a formula once?
Also, if you're going to the trouble of writing VBA to generate a formula, it may make more sense to just do the sum entirely in VBA code.
If not, try this:
Sub GenerateTheFormula()
Dim x, Formula
Formula = "=SUM(" 'Formula begins with =SUM(
For x = 3 To Sheets.Count
Formula = Formula & Sheets(x).Name & "!A1," 'Add SheetName and Cell and Comma
Next x
Formula = Left(Formula, Len(Formula) - 1) & ")" 'Remove trailing comma and add parenthesis
Range("B1").Formula = Formula 'Where do you want to put this formula?
End Sub
Results:
The functions return strings and not actual worksheets. The Worksheet does not parse strings well. So add a third function that uses the Evaluate function:
Function MySum(rng As Range)
MySum = Application.Caller.Parent.Evaluate("SUM(" & FirstSheet & ":" & LastSheet & "!" & rng.Address & ")")
End Function
Then you would simply call it: MySum(A1)
It uses the other two function you already have created to create a string that can be evaluated as a formula.
I didn't understand ur question completely but As I understood u have different sheets of different clients which contains supoose column 1 date and column 2
contains hours on that particular date wise hours and a final sheet which column1 contains name of client and column 2 contains total hoursPlease try it
Sub countHours()
Dim last_Row As Integer
Dim sum As Double
sum = 0
'Because I know number of client
For i = 1 To 2 'i shows client particular sheet
last_Row = Range("A" & Rows.Count).End(xlUp).Row
Sheets(i).Activate
For j = 2 To last_Row
'In my Excel sheet column 1 contains dates and column 2 contains number of hours
sum = sum + Cells(j, 2)
'MsgBox sum
Next j
'Sheet 3 is my final sheet
ThisWorkbook.Sheets(3).Cells(i + 1, 2).Value = sum
sum = 0
Next i
End Sub
Happy Coding :
Right - this is a tricky one to phrase so I'm going to use a couple of images to help me.
In Columns A and B is a varying list of team names and the number of players each team has.
Column D contains the desired output.
I need a formula, to be inserted into Cell D2 and dragged down as far as the total of Column B, to return the team names - but crucially to allow a number of rows beneath which return blank. The number of blank rows beneath is effectively equal to 1 - the number of players in that team.
I have given it some thought, but can't come up with a suitable formula. Any ideas?
Also suggestions for a better title are welcome.
The following VBA function will do exactly what you want. Let me know if any part of it is not clear to you.
Sub teamRows()
Dim colDRowNumber As Integer
Dim i As Integer
Dim teamName As String
Dim numberOfRows As Integer
Dim HowFar As Integer
' Loop through the teams in column A
HowFar = Application.WorksheetFunction.CountA(Range("A:A"))
' Variable to keep count of rows in column D
colDRowNumber = 2
For i = 2 To HowFar
' Get the team's name and number of rows
teamName = Range("A" & i).Value
numberOfRows = Range("B" & i).Value
' Fill in the team's name in column D
Range("D" & colDRowNumber).Value = teamName
' Increase the row number by the number of empty rows required
colDRowNumber = colDRowNumber + numberOfRows
Next i
End Sub
A complex but short attempt - I wanted to avoid loops.
Example below works on A2 to A20
y = Split(Join(Application.Transpose(Application.Evaluate("=index(substitute(substitute(substitute(REPT(A2:A20 &"","",B2:B20),A2:A20&"","",""X"",1),A2:A20,""""),""X"",A2:a20),0,1)")), ","), ",")
[d2].Resize(UBound(y)) = Application.Transpose(y)
I have a pretty basic loop that I am using to run some random scenarios. On one of my worksheets I am using the =Rand() function to generate random numbers/scenarios for my workbook. What I am trying to program from there is a macro that refreshes the workbook (and the random set of numbers) and then deposits my results onto my worksheet each time the scenario is run. Ultimately, I'd like to be able to run/generate 100,000 random scenarios and deposit the results. Here is what I've coded so far:
Sub Run()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim wksInput As Worksheet, i As Integer
Set wksInput = Sheets("Input")
For i = 2 To 102
Application.Calculate
With wksInput
.Range("P" & i).Value = .Range("J35").Value
.Range("Q" & i).Value = .Range("K35").Value
.Range("R" & i).Value = .Range("L35").Value
.Range("S" & i).Value = .Range("G32").Value
End With
Next i
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
What I have here works just fine, except that it takes 23 seconds to run just 100 scenarios. Based on my calculation that would require over 6 hours of run time to get my 100,000 random scenarios.
My question is does anyone know of a clever way to either change the code to run more efficiently or optimize what I already have. I done all the basic things like turning calculation to manual and turning off screenupdating.
Thanks for your ideas.
The problem is this line:
Application.Calculate
As it's placed inside the For i = 2 To 102, it means that for every row you add all the =rand() functions of the spreadsheet are recalculated.
May I suggest you to generate the random numbers within the code, using the Rnd() built-in function of VBA. Like that, you will generate only the random input you need avoiding to generate the N-1 other inputs that you will regenerate anyway at the Next loop when calling Application.Calculate once again.
what might that look like?
This is the logic (I cannot tell you specifically because you didn't show your whole code/spreadsheet nor the logic behind this random generation): let's say that you have three random numbers in the cells A1, A2 and A3. They are all calculated with a function =Rand() inside the cell.
Now, with your code, you want that in B1, B2 and B3 there is the sum of the random number in A + 1.
the Excel solution (i.e. Excel calculates the random inputs with the function =Rand()):
For j = 1 To 3
Application.Calculate '<-- this re-calculates 3 =rand(), but you need only the one you're going to use right after (==j)
Range("B" & j) = Range("A" & j) + 1
Next j
the VBA solution (i.e. the random numbers are not in the Excel spreadsheet but calculated through VBA):
Randomize
For j = 1 To 3
Range("A" & j) = Rnd() '<-- you insert the random value in A1, A2...
Range("B" & j) = Range("A" & j) + 1 '<-- you use it
Next j
The Excel solution calculates 3 random functions for 3 times, i.e. 9 iterations. The VBA solution calculates 1 random function for 3 times, i.e. 3 iterations.
I let you imagine the multiplication for 100,000 scenarios with 100 data each.