Write Excel formula into cell using VBA - excel

I am trying to overwrite wrong Excel formula.
I copied the formula from the cell into the code and placed double quotes.
Already read that I have to type two times " for getting a " into the formula. I can't tell what is really going on, because of companies compliance but the code should do it.
Imagine there are 180 components with the same 18 function in cells. By deleting some components I lost the reference and instead of writing every formula again, I try to do this with VBA.
Sub nachtrag()
Dim i As Integer
Dim j As Integer
Dim Start As Integer
Start = 4
Dim Bezug As Integer
For i = 0 To 179
Bezug = Worksheets("QK-Daten").Range("R" & ((i * 18) + 18) + Start).Value
For j = 1 To 17
Worksheets("QK-Daten").Range("Z" & j + (i * 18) + Start).Value = "=WENN(R" & Bezug & "="""";"""";SVERWEIS(R" & Bezug & ";'QK-Tabelle'!$B$3:$C$123;2;FALSCH))*(R" & j + (i * 18) + Start & "/R" & Bezug & ")+((N" & j + (i * 18) + Start & "+O" & j + (i * 18) + Start & ")*0,3+(P" & j + (i * 18) + Start & "+Q" & j + (i * 18) + Start & ")*0,1)"
Next j
Worksheets("QK-Daten").Range("z" & ((i * 18) + 18) + Start).Copy
Worksheets("QK-Daten").Range("z" & ((i * 18) + 18) + Start).PasteSpecial Paste:=xlValues
Next i
End Sub

Try writing the formula with placeholders in the string and then use Replace() to substitute the values.
Option Explicit
Sub nachtrag()
Dim ws As Worksheet, cell As Range, s As String
Dim Bezug As Long, Start As Long
Dim i As Long, j As Long, r As Long
' formula
Const F = "=IF(R<bezug>="""";"""";VLOOKUP(R<bezug>;'QK-Tabelle'!$B$3:$C$123;2;FALSE))" & _
"*(R<r>/R<bezug>)+((N<r>+O<r>)*0,3+(P<r>+Q<r>)*0,1)"
Start = 4
Set ws = Worksheets("QK-Daten")
With ws
Set cell = .Range("R" & Start)
For i = 0 To 179
Bezug = cell.Offset(18).Row 'Value
For j = 1 To 17
r = j + (i * 18) + Start
s = Replace(F, "<bezug>", Bezug)
s = Replace(s, "<r>", r)
cell.Offset(j, 8).Formula = s 'Z
Next j
' not sure what this is doing
' .Range("z" & ((i * 18) + 18) + Start).Copy
' .Range("z" & ((i * 18) + 18) + Start).PasteSpecial Paste:=xlValues
cell.Offset(18, 8).Value = cell.Offset(18, 8).Value
' next component
Set cell = cell.Offset(18)
Next i
End With
MsgBox "Done", vbInformation
End Sub

Related

Problem with finding similar numbers in 2 columns in vba

i have problem with my code in vba. I have to find how much similar numbers are in column 1 and 2, but for example Column 1 (6,6,34,21,23,40) and column2 (49,34,6,9,6,20) should write 3 cause there are pairs 6-6, 6-6 and 34-34. I know its messy explenation but i hope its understandable. My code so far is:
Sub totolotek()
Dim i As Integer
Dim x As Integer
Dim j As Integer
Dim liczba As Integer
Dim suma As Integer
Dim ileLosowan As Integer
Range("B2:C7").Interior.Color = RGB(135, 134, 125)
Range("B2:B7").Font.ColorIndex = 3
Range("C2:C7").Font.ColorIndex = 5
ileLosowan = 7
Randomize
For i = 2 To ileLosowan
x = Int(Rnd * (49) + 1)
Range("c" & i) = x
Next i
For i = 2 To 7
liczba = Range("c" & i)
For j = 2 To 7
liczbe = Range("b" & j)
If liczbe = liczba Then
Range("c" & i).Interior.Color = RGB(255, 255, 0)
Range("b" & j).Interior.Color = RGB(255, 255, 0)
suma = suma + 1
End If
Next j
Next i
Range("c" & 9) = suma
End Sub
Try this. I invested some time and I added some lines of code. The macro find all the number pairs.
Example (6,6,3,4,2) (2,3,6,9,0) --> results 3: (6-6, 3-3, 2-2)
Sub totolotek()
Dim i As Integer
Dim x As Integer
Dim j As Integer
Dim liczba As Integer
Dim suma As Integer
Dim ileLosowan As Integer
Dim str_B As String, str_C As String, str_BC As String
Dim max_rand As Long
ileLosowan = 20 ' you can change the number of element in the column
max_rand = 49 ' max randum number
start_row = 2 'start_row
str_BC = "B2:C" & ileLosowan
str_B = "B2:B" & ileLosowan
str_C = "C2:C" & ileLosowan
Range(str_BC).Interior.Color = RGB(135, 134, 125)
Range(str_B).Font.ColorIndex = 5
Range(str_C).Font.ColorIndex = 5
Randomize
For i = start_row To ileLosowan
x = Int(Rnd * (max_rand) + 1)
Range("C" & i) = x
Next i
For i = start_row To ileLosowan
x = Int(Rnd * (max_rand) + 1)
Range("B" & i) = x
Next i
liczba_array = Range("B" & start_row & ":B" & ileLosowan).Value2
liczbe_array = Range("C" & start_row & ":C" & ileLosowan).Value2
ReDim ID_array(1 To 1)
ID_array(1) = max_rand + 1
Count = 1
For i = 1 To UBound(liczba_array, 1)
For j = 1 To UBound(liczbe_array, 1)
For k = 1 To UBound(ID_array, 1)
If ID_array(k) = j Then
GoTo out
End If
Next k
If liczba_array(i, 1) = liczbe_array(j, 1) Then
Range("B" & (start_row + i - 1)).Interior.Color = RGB(150 + Count * 20, 0, 0)
Range("C" & (start_row + j - 1)).Interior.Color = RGB(150 + Count * 20, 0, 0)
suma = suma + 1
ID_array(Count) = j
Count = Count + 1
ReDim Preserve ID_array(1 To Count)
Exit For
End If
Next j
out:
Next i
Range("C" & ileLosowan + 2) = suma
End Sub
Something like this will do what you're after. Just incorporate it into you're code cause I don't really know what's going on there.
Dim i As Long, j As Long, arr As Variant, Total As Integer
For i = 2 To 7 'Rows to loop through in the column
Total = 0
arr = Split(Range("A" & i), ",") 'Split column A using the comma
For j = 0 To UBound(arr) 'Loop through the split values
If InStr(Range("B" & i), arr(j)) > 0 Then 'Find if value is within other column
Total = Total + 1 'If it is, add 1 to total
End If
Next j
Range("C" & i) = Total 'Write total to another column on same row
Next i
Or if you want a basic function for it that you can use in your sheet you can use this:
Public Function CountMatches(Cell As String, Rng As Range, Optional Delim As String)
Dim i As Long, j As Long, arr As Variant, Total As Integer
If Delim = "" Then Delim = ","
If Rng.Count > 1 Then
CountMatches = "Please choose 1 cell to compare to."
Exit Function
End If
Total = 0
arr = Split(Cell, Delim) 'Split column A using the comma
For j = 0 To UBound(arr) 'Loop through the split values
If InStr(Rng, arr(j)) > 0 Then 'Find if value is within other column
Total = Total + 1 'If it is, add 1 to total
End If
Next j
CountMatches = Total
End Function
Use it like =CountMatches(A1,B1,",")

Type Mismatch: Range Formula

I am completely at a loss as to why I am getting the "type mismatch" error.
The error appears on the Range(RelAddy).Formula line.
Sub CallingUserformAssignJC()
BeforeLastRow = Sheets("Information").Cells(Rows.Count, 19).End(xlUp).Row
Sheets("Information").Range("U2:U" & BeforeLastRow).ClearContents
LastRowAC = Sheets("Information").Cells(Rows.Count, 19).End(xlUp).Row
LastCol = Sheets("Today").Cells(1, Columns.Count).End(xlToLeft).Column
For j = 1 To LastCol
CurrLastRow = Sheets("Today").Cells(Rows.Count, j).End(xlUp).Row
startAddy = Sheets("Today").Cells(2, j + 1).Address
endAddy = Sheets("Today").Cells(CurrLastRow, j + 1).Address
RelAddy = Sheets("Today").Cells(CurrLastRow + 1, j + 1).Address
Range(RelAddy).Formula = "=COUNTA(" & Sheets("Today").Range(startAddy, endAddy) & ")"
unassignedMilestone = Sheets("Today").Cells(CurrLastRow + 1, j + 1).Value
Do While unassignedMilestone <> 0
frmAssignJC.Show
frmAssignJC.Hide
Loop
j = j + 3
Next j
End Sub
I have looked at the locals window, and startAddy, endAddy, and RelAddy are all type Variant/String. Any help would be appreciated thank you.
The problem is in Range("B2").Formula = "=COUNTA(" & Sheets("Today").Range(startAddy, endAddy) & ")"
Try Range("B2").Formula = "=COUNTA(" & Sheets("Today").Range(startAddy, endAddy).Address & ")"
In order to use a formula you need to get the Address of the range instead of just the range

Shuffling a 2D array

I have the follow script to put a list of people with there know skills in an array and then match the first match with a customer with the same skill. Every time it runs the results are the same. I would like to have it be a random order of the array, but keeping the two columns in the array together. How can I shuffle(rearrange) the array that keeps the rows in the array the same? Or would it be better to erase the array, randomly sort the columns and set the array back up?
Sub Assign()
Dim arOne()
ReDim arOne(1000, 15)
Dim o As Integer
Dim p As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
p = 0
o = 0
For i = 2 To 920
If Cells(i, 12).Value <> Cells(i - 1, 12) Then
p = p + 1
arOne(p, 0) = Cells(i, 12).Value
arOne(p, 1) = Cells(i, 13).Value
o = 2
Else
arOne(p, o) = Cells(i, 13).Value
o = o + 1
End If
Next
For i = 2 To 612
For o = LBound(arOne, 1) + 1 To UBound(arOne, 1)
If arOne(o, 0) <> "" Then
iUsed = Application.WorksheetFunction.CountIf(Range("C2:C" & i), "=" & arOne(o, 0))
If iUsed < Application.WorksheetFunction.VLookup(arOne(o, 0), Range("Q2:R62"), 2, False) Then
For j = LBound(arOne, 2) + 1 To UBound(arOne, 2)
If arOne(o, j) = Cells(i, 2).Value Then
Cells(i, 3).Value = arOne(o, 0)
ActiveSheet.Calculate
GoTo NextIR
End If
Next j
End If
End If
Next o
NextIR:
Next i
End Sub
Multiple loops and multiple access to range objects makes your code very, very slow (I don't know if performance is important).
I would read all necessary data to arrays and use filter and rnd to get a random person with the relevant skill:
Option Explicit
Sub PeopleBusiness()
Dim People, Customers, FilterArray
Dim I As Long, Idx As Long
People = Application.Transpose([L2:L920 & "|" & M2:M8])
Customers = Range("A2:C612").Value2
For I = 1 To UBound(Customers, 1)
FilterArray = Filter(People, Customers(I, 2))
If UBound(FilterArray) > -1 Then
Idx = Round(Rnd() * UBound(FilterArray), 0)
Customers(I, 3) = Left(FilterArray(Idx), InStr(1, FilterArray(Idx), "|") - 1)
End If
Next I
Range("A2:C612").Value = Customers
End Sub
I was able to get done what I needed by erasing the array and redimming it after sorting the data based on a rand() number in the table. It takes about 15 minutes to run 7000 assignment but it is a lot better than 7+ hours it takes to do manually.
Sub Assign()
Dim arOne()
ReDim arOne(1000, 15)
Dim o As Integer
Dim p As Integer
Dim StartTime As Double
Dim MinutesElapsed As String
Application.Calculation = xlAutomatic
StartTime = Timer
NextIR:
ReDim arOne(1000, 15)
p = 0
o = 0
QAlr = Sheets("Sheet1").Range("L" & Rows.Count).End(xlUp).Row
For I = 2 To QAlr
If Cells(I, 12).Value <> Cells(I - 1, 12) Then
p = p + 1
arOne(p, 0) = Cells(I, 12).Value
arOne(p, 1) = Cells(I, 13).Value
o = 2
Else
arOne(p, o) = Cells(I, 13).Value
o = o + 1
End If
Next
AQAlr = Sheets("Sheet1").Range("C" & Rows.Count).End(xlUp).Row
AgtLr = Sheets("Sheet1").Range("A" & Rows.Count).End(xlUp).Row
For I = AQAlr + 1 To AgtLr
For o = LBound(arOne, 1) + 1 To UBound(arOne, 1)
If arOne(o, 0) <> "" Then
iUsed = Application.WorksheetFunction.CountIf(Range("C2:C" & I), "=" & arOne(o, 0))
If iUsed < Application.WorksheetFunction.VLookup(arOne(o, 0), Range("Q2:R62"), 2, False) Then
For j = LBound(arOne, 2) + 1 To UBound(arOne, 2)
If arOne(o, j) = Cells(I, 2).Value Then
Cells(I, 3).Value = arOne(o, 0)
ActiveSheet.Calculate
Erase arOne()
ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort.SortFields.Add _
Key:=Range("Table1[[#All],[Random '#]]"), SortOn:=xlSortOnValues, Order:= _
xlDescending, DataOption:=xlSortTextAsNumbers
With ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1").Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
GoTo NextIR
End If
Next j
End If
End If
Next o
Next I
MinutesElapsed = Format((Timer - StartTime) / 86400, "hh:mm:ss")
MsgBox "Assignments completed in " & MinutesElapsed & " minutes", vbInformation
End Sub
Not entirely sure I got your set-up right but you can try this:
Option Explicit
Sub Assign()
Randomize
Range("C2", Range("C" & Rows.Count).End(xlUp)).ClearContents
Dim R1 As Range: Set R1 = Range("L2:M920") 'People skill table
Dim R2 As Range: Set R2 = Range("A2:B612") 'Cusotmers skill talbe
Dim D0 As Object: Set D0 = CreateObject("scripting.dictionary")
Dim i As Integer, j As Integer, Rand as Integer
For i = 1 To R2.Rows.Count
Rand = Int(R1.Rows.Count * Rnd + 1)
For j = 1 To R1.Rows.Count
If R1.Cells(Rand, 2) = R2(i, 2) And Not D0.exists(Rand) Then
R2.Cells(i, 2).Offset(0, 1) = R1(Rand, 1)
D0.Add Rand, Rand
Exit For
End If
Rand = (Rand Mod R1.Rows.Count) + 1
Next j
Next i
End Sub
The idea is to check the people skill list starting from a random point and making sure a key is not used twice.
EDIT:
According to your comment I assume a "people / skill" can then be assigned more than once as there are 7000+ customers ?
Code below randomly assign with a fairly good distribution 1500 peoples to 7000 customers in +/- 1 second.
Have a try and see if you can adapt it to your project.
Option Explicit
Sub Assign()
Application.ScreenUpdating = False
Dim Start: Start = Timer
Randomize
Range("C2:C99999").ClearContents
Dim D1 As Object
Dim R1 As Range: Set R1 = Range("L2", Range("M" & Rows.Count).End(xlUp))
Dim R2 As Range: Set R2 = Range("A2", Range("B" & Rows.Count).End(xlUp))
Dim T1: T1 = R1
Dim T2: T2 = R2
Dim T3()
Dim a As Integer: a = 1
Dim i As Integer, j As Integer, k As Integer, Rnd_Val As Integer, j_loop As Integer
For i = 1 To (Int(R2.Rows.Count / R1.Rows.Count) + 1)
Set D1 = CreateObject("scripting.dictionary")
For j = (R1.Rows.Count * i - R1.Rows.Count + 1) To R1.Rows.Count * i
ReDim Preserve T3(1 To j)
Rnd_Val = Int(Rnd * R1.Rows.Count + 1)
For k = 1 To R1.Rows.Count
If T1(Rnd_Val, 2) = T2(j, 2) And Not D1.exists(Rnd_Val) And T3(j) = "" Then
T3(j) = T1(Rnd_Val, 1)
D1.Add Rnd_Val, Rnd_Val
Exit For
End If
Rnd_Val = (Rnd_Val Mod R1.Rows.Count) + 1
Next k
If T3(j) = "" Then
For k = 1 To R1.Rows.Count
If T1(Rnd_Val, 2) = T2(j, 2) Then
T3(j) = T1(Rnd_Val, 1)
Exit For
End If
Rnd_Val = (Rnd_Val Mod R1.Rows.Count) + 1
Next k
End If
a = a + 1
If a > R2.Rows.Count Then GoTo EndLoop
Next j
Set D1 = Nothing
Next i
EndLoop:
Range("C2").Resize(UBound(T3), 1) = Application.Transpose(T3)
Debug.Print Timer - Start
Application.ScreenUpdating = True
End Sub

method range of object _global failed when trying to use a String Object within Range object

I've been getting a "method range of object _global failed" message when trying to use a combination of range objects and strings. I'm trying to iterate through several worksheets, copy and transpose each row from the worksheet, stack the transposed rows into a single column, then move to the next sheet to grab its rows and paste them to the next column over.
Dim CopyRng, pasteRng, Outnum, compsht As String
Dim myRng, PstRng As Range
For j = 5 To 10
For i = 1 To tot_centers
Outnum = "out" & j
CopyRng = "ThisWorkbook.Sheets(""" & Outnum & """).Cells(" & i & ", 2),
ThisWorkbook.Sheets(""" & Outnum & """).Cells(" & i & ", " & tot_days + 2 & ")"
Set myRng = Range(CopyRng)
Sheets(Outnum).Range(myRng).Copy 'THIS IS WHERE DEBUG HITS ERROR
pasteRng = "ThisWorkbook.Sheets(""" & "Compiled Data" & """).Cells(" & ((tot_days * (i - 1)) + (i + 1)) & ", " & j - 2 & ")"
Set PstRng = Range(pasteRng) 'AND I'LL PROBABLY GET THE SAME ERROR HERE
PstRng.PasteSpecial Transpose:=True
Next i
Next j
Something like this (tot_days/tot_centers variable names need resolving)
Dim CopyRng, pasteRng, Outnum, compsht As String
Dim myRng, PstRng As Range, j, i
Dim shtOut As Worksheet
For j = 5 To 10
Set shtOut = ThisWorkbook.Sheets("out" & j)
For i = 1 To tot_centers '<< tot_days ?
shtOut.Cells(i, 2).Resize(1, tot_days + 1).Copy '<< tot_centers?
ThisWorkbook.Sheets("Compiled Data").Cells(tot_days * (i - 1) + (i + 1), _
j - 2).PasteSpecial Transpose:=True
Next i
Next j
For anybody who sees this post and wants to know how to open sheets, grab multiple rows one at a time, and stack them into individual columns, here's how the code turned out:
Dim Outnum As String
For j = 5 To 10 'use worksheets with outputs 5 through 10
For i = 1 To tot_centers 'in this case, tot_centers was declared earlier in the code and is and integer I count from a sheet
Outnum = "out" & j
Sheets(Outnum).Range(Sheets(Outnum).Cells(i, 2), Sheets(Outnum).Cells(i, tot_days + 2)).Copy
Sheets("Compiled Data").Range(Sheets("Compiled Data").Cells((tot_days * (i - 1)) + (i + 1), j - 1), Sheets("Compiled Data").Cells((tot_days * (i - 1)) + (i + 1), j - 1)).PasteSpecial Transpose:=True
Next i
Next j
End Sub

How 16.06.2016 is bigger than 29.10.2016

I have a macro to fill dates background if they are not forward than today. It works nicely but, however, just in one page, DateValues are not compared correctly.
I tried to show the result with MessageBoxes, it says 16.06.2016 is bigger than 29.10.2016
My macro:
Sub DolguRenkleri(ByVal StartIndex As Integer, ByVal EndIndex As Integer)
Dim Tarih As String
Dim Formul As String
Dim Formul2 As String
Tarih = Left(Now, 10)
For i = StartIndex To EndIndex - 1
MsgBox (Cells(i, 2).Value > DateValue(Tarih))
If Cells(i, 2) <= DateValue(Tarih) Then
With Range("A" + CStr(i), "H" + CStr(i))
.Interior.ColorIndex = 6
End With
Formul = "=TOPLA(D" + CStr(i + 1) + ":D" + CStr(EndIndex - 1) + ")"
Formul2 = "=F6-A" + CStr(i)
Else: With Range("A" + CStr(i), "H" + CStr(i))
.Interior.ColorIndex = 2
End With
End If
Next i
Range("F1").FormulaLocal = Formul
Range("F7").FormulaLocal = Formul2
End Sub
it must be that "16.06.2016" string in cell B10 is not recognized as a real Date value, notwithstanding you may have selected that cell and assigned it a "Date" format
in this case, use
If DateValue(Replace(Cells(i, 2).Value, ".", "/")) <= DateValue(Tarih) Then

Resources