Converted the JSON Parsing Code to Arrays and getting error - excel

I was working on a project to extract the data from API and Parsing it through the relevant column. The first one is working very fine but its optimizing speed is extremely slow.
so i though to convert it into arrays for fast processing but geeting Run-time error 9 Subscript out of range`
Your help will be much appreciated to fix the issue.
First code with slow optimization.
Dim json As Object
Dim timeEntry As Object
Dim ti As Object
Dim lastRow As Long
Dim myValue As String
Set json = JsonConverter.ParseJson(Data)
i = 2
lastRow = Sheet2.Range("A1").End(xlUp).Row
For Each timeEntry In json("timeentries")
With Sheet2.Cells(i, 1)
.Value = timeEntry("projectName")
.Offset(0, 4).Value = timeEntry("taskName")
.Offset(0, 8).Value = timeEntry("description")
.Offset(0, 9).Value = timeEntry("clientName")
End With
Set ti = timeEntry("timeInterval")
With Sheet2.Cells(i, 1)
.Offset(0, 10).Value = ti("start")
.Offset(0, 6).Value = ti("duration")
End With
i = i + 1
Next timeEntry
Second code with Arrays and getting error
Dim json As Object
Dim timeEntry As Object
Dim ti As Object
Dim lastRow As Long
Dim myValue As String
Set json = JsonConverter.ParseJson(Data)
i = 2
lastRow = Sheet2.Range("A1").End(xlUp).Row
Dim dataArray() As Variant
ReDim dataArray(1 To lastRow, 1 To 12)
For Each timeEntry In json("timeentries")
dataArray(i, 1) = timeEntry("projectName")
dataArray(i, 5) = timeEntry("taskName")
dataArray(i, 9) = timeEntry("description")
dataArray(i, 10) = timeEntry("clientName")
Set ti = timeEntry("timeInterval")
dataArray(i, 11) = ti("start")
dataArray(i, 7) = ti("duration")
i = i + 1
Next timeEntry
Sheet2.Range("A2").Resize(lastRow, 12).Value = dataArray

Size array to number of entries
Sub demo()
Dim json As Object, t As Object
Dim data, i As Long, n As Long
data = "{'timeentries':[" & _
"{'projectName':'Name1','taskName':'Task1','timeInterval':{'start':'08:00','duration':'123'}}," & _
"{'projectName':'Name2','taskName':'Task2','timeInterval':{'start':'09:00','duration':'234'}}," & _
"{'projectName':'Name3','taskName':null,'timeInterval':{'start':'10:00','duration':'345'}}]}"
Set json = JsonConverter.ParseJson(data)
n = json("timeentries").Count
If n < 1 Then
MsgBox "No timeentries in JSON", vbCritical
Exit Sub
End If
Dim dataArray() As Variant
ReDim dataArray(1 To n, 1 To 6)
i = 1
For Each t In json("timeentries")
dataArray(i, 1) = t("projectName") '1
If Not IsNull(t("taskName")) Then
dataArray(i, 2) = t("taskName") '5
End If
dataArray(i, 3) = t("description") '9
dataArray(i, 4) = t("clientName") '10
dataArray(i, 5) = t("timeInterval")("start") '11
dataArray(i, 6) = t("timeInterval")("duration") '77
i = i + 1
Next
' columns
Dim col: col = Array(1, 5, 9, 10, 11, 7)
For i = 0 To UBound(col)
Sheet2.Cells(2, col(i)).Resize(n) = WorksheetFunction.Index(dataArray, 0, i + 1)
Next
End Sub

Related

Subscript out of Range - Run time error 9 ReDim function

Good morning, I'm new to this VBA world, and I came across this error in the code below, could someone help me with this (sorry for the google translator).
Error in the firt ReDim
Sub sofar2()
'Dim t As Single
't = Timer
qntinv = Cells(10, 2).Value - 1
maxoverload = Cells(11, 2).Value
vpartida = Cells(12, 2).Value
voperacao = Cells(13, 2).Value
vmpmax = Cells(14, 2).Value
vocmax = Cells(15, 2).Value
minoverload = Cells(16, 2).Value
taminfo = Cells(17, 2).Value - 1
correntemax = Cells(18, 2).Value 'CORRENTE MAXIMA 200
correcaocorrente = 1
folgatrafo = Cells(19, 2).Value
Dim modulo(4) As Double
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim aux As Integer
Dim Infoinv() As Double
Dim Inv() As String
Dim MaxString() As Double
Dim MinMod() As Double
Dim MaxMod() As Double
Dim LimitMod() As Integer
Dim LimitModMPPT() As Double
Dim qntmod() As Integer
Dim limitmodmin() As Double
ReDim Infoinv(taminfo, qntinv)
ReDim Inv(1, qntinv)
'Preenche matriz inversores, verificar qnts inversores existem e dados presentes
For i = 0 To qntinv
For j = 0 To taminfo
Infoinv(j, i) = Worksheets("D.Inv.Comp").Cells(j + 2, i + 3).Value
Next j
Inv(1, i) = Worksheets("D.Inv.Comp").Cells(1, i + 3).Value
Next i

VBA Excel: enumerate total number of duplicates. Count and sum

On the left is the hypothetical database. On the right is the result I would like to obtain.
I would like to print all of the items of type B, as well as the sum and the count.
I'm stuck and I'm not able to go ahead. Could you please help me out? Thanks.
Private Sub CommandButton1_Click()
Dim dicDistincts As Scripting.Dictionary, _
dicDuplicates As Scripting.Dictionary
Set dicDistincts = New Scripting.Dictionary
Set dicDuplicates = New Scripting.Dictionary
Dim i As Integer
For i = 2 To 10
If Cells(i, 1).Value = "B" Then
If Not dicDistincts.Exists(Cells(i, 2).Value) Then
dicDistincts.Add Key:=Cells(i, 2).Value, Item:=Cells(i, 2).Value
Else
dicDuplicates.Add Key:=Cells(i, 2).Value, Item:=Cells(i, 2).Value
End If
End If
Next i
For i = 0 To dicDuplicates.Count - 1
Cells(i + 1, 9).Value = WorksheetFunction.CountIfs(Range("a2:a10"), "B", Range("b2:b10"), dicDistincts.keys(i))
Next i
End Sub
EDIT: I tried with countifs but it return 0 for banana, apple and strawberry
EDIT 2: I corrected the countifs. Now it works.
If you must use dictionaries then you could do this with a single dictionary, storing the counts and quantities as array as the values in the dictionary.
Private Sub CommandButton1_Click()
Dim dic As Scripting.Dictionary
Dim arrData()
Dim i As Long
Dim ky As Variant
Set dic = New Dictionary
For i = 2 To 10
If Cells(i, 1).Value = "B" Then
ky = Cells(i, 2).Value
If Not dic.Exists(ky) Then
arrData = Array(1, Cells(i, 3).Value)
Else
arrData = dic(ky)
arrData = Array(arrData(0) + 1, arrData(1) + Cells(i, 3).Value)
End If
dic(ky) = arrData
End If
Next i
Range("A1:C1").Copy Range("E1:G1")
For i = 0 To dic.Count - 1
Range("E" & i + 2) = dic.Keys(i)
Range("F" & i + 2).Resize(, 2) = dic.Items(i)
Next i
End Sub
Unique Sum and Unique Count with Double Dictionary
Option Explicit
Private Sub CommandButton1_Click()
Dim rg As Range
With Range("A1").CurrentRegion
Set rg = .Resize(.Rows.Count - 1).Offset(1)
End With
Dim Data As Variant: Data = rg.Value
Dim cDict As Object: Set cDict = CreateObject("Scripting.Dictionary")
Dim sDict As Object: Set sDict = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 1 To UBound(Data, 1)
If Data(i, 1) = "B" Then
cDict(Data(i, 2)) = cDict(Data(i, 2)) + 1 ' Count
sDict(Data(i, 2)) = sDict(Data(i, 2)) + Data(i, 3) ' Sum
End If
Next i
ReDim Data(1 To cDict.Count, 1 To 3)
i = 0
Dim Key As Variant
For Each Key In cDict.Keys
i = i + 1
Data(i, 1) = Key
Data(i, 2) = sDict(Key)
Data(i, 3) = cDict(Key)
Next Key
With Range("E2").Resize(, 3)
.Resize(i).Value = Data
.Resize(.Worksheet.Rows.Count - .Row - i + 1).Offset(i).ClearContents
End With
End Sub
This should work it uses loops through all bs and addes them if to the other list
Sub countBs()
Dim Bs As Range 'list of the line of all Bs
Dim B As Range 'each indiviual b in the B list
Dim Item As Range 'each indivual item
Dim adder As Range 'resturns nothing if b not fond in times
Set Bs = Range("a2", Range("a2").End(xlDown)) 'you can also change this ofcourse to a specifici range or user selected
For Each B In Bs
If B = "B" Then
Set adder = Range("g2", Range("g2").End(xlDown)).Find(B.Offset(0, 1))
If adder Is Nothing Then
If Range("g2") = "" Then
Set Item = Range("g2")
Else
Set Item = Range("g1").End(xlDown).Offset(1, 0)
End If
Item.Resize(1, 2).Value = B.Offset(0, 1).Resize(1, 2).Value
Item.Offset(0, 2) = 1
Else
adder.Offset(0, 1).Value = adder.Offset(0, 1).Value + B.Offset(0, 2).Value
adder.Offset(0, 2).Value = adder.Offset(0, 2).Value + 1
End If
End If
Next B
End Sub

Populate Listbox Multiple Column With Criteria

I have a 'textbox' (lstDetalhe) in my 'userform' (frmFormDetalhe) and I would like to display only data whose id is the same as ChaveEstrangeira...
Sub Detalhe()
Dim UltimaLinha As Integer
Dim Rng As Range
Dim ChaveEstrangeira As Integer
ChaveEstrangeira = frmForm.lstCarteira.Value
Set Resumo = Sheets("Resumo")
UltimaLinha = [Counta(Resumo!A:A)]
For i = 1 To UltimaLinha
If Sheets("Resumo").Range("B" & i).Value = ChaveEstrangeira Then
frmFormDetalhe.lstDetalhe.ColumnCount = 5
frmFormDetalhe.lstDetalhe.AddItem Sheets("Resumo").Range("C" & i).Value
End If
Next i
End Sub
it turns out that only one column returns to me. How to return multiple columns?
----EDIT---
I did it this way:
Sub Detalhe()
Dim UltimaLinha As Integer
Dim ChaveEstrangeira As Integer
Dim Resumo As Object
Dim i
ChaveEstrangeira = frmForm.lstCarteira.Value
UltimaLinha = [Counta(Resumo!A:A)]
Set Resumo = Sheets("Resumo")
With frmFormDetalhe
.lstDetalhe.ColumnCount = 11
.lstDetalhe.ColumnHeads = False
.lstDetalhe.ColumnWidths = "20;55;50;50;50;60;55;75;50;50"
For i = 2 To UltimaLinha
If Sheets("Resumo").Range("B" & i).Value = ChaveEstrangeira Then
.lstDetalhe.AddItem 'Resumo.Range("A1:K1").Cells(i, 1)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 0) = Resumo.Range("A1:K1").Cells(i, 1)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 1) = Resumo.Range("A1:K1").Cells(i, 2)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 2) = Resumo.Range("A1:K1").Cells(i, 3)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 3) = Resumo.Range("A1:K1").Cells(i, 4)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 4) = Resumo.Range("A1:K1").Cells(i, 5)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 5) = Resumo.Range("A1:K1").Cells(i, 6)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 6) = Resumo.Range("A1:K1").Cells(i, 7)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 7) = Resumo.Range("A1:K1").Cells(i, 8)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 8) = Resumo.Range("A1:K1").Cells(i, 9)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 9) = Resumo.Range("A1:K1").Cells(i, 10)
.lstDetalhe.List(.lstDetalhe.ListCount - 1, 10) = Resumo.Range("A1:K1").Cells(i, 11) 'ERROR HERE
End If
Next i
End With
End Sub
But it seems that this last line is reporting an error ...when I change 10 to a number of 1 just any number it returns without error...
Try this code, please. It is good to create a habit of using Long variables instead of Integer. VBA loads memory with Longs, anyhow and no benefit of using Integer. Since no benefit from memory load point of view, a Long variable offer more space. Then, declare Resumo variable As Worksheet:
Sub Detalhe()
Dim UltimaLinha As Long, ChaveEstrangeira As Long, Resumo As Worksheet
Dim arrList As Variant, i As Long, j As Long, k As Long
Set Resumo = Sheets("Resumo")
ChaveEstrangeira = CLng(frmForm.lstCarteira.value)
UltimaLinha = Resumo.Range("A" & Rows.count).End(xlUp).Row
ReDim arrList(1 To 11, 1 To UltimaLinha)'initial array dim, but with last dimension being rows. Only the last dimension can be ReDim Preserve
For i = 2 To UltimaLinha
If Resumo.Range("B" & i).value = ChaveEstrangeira Then
k = k + 1 'array row to be filled
For j = 1 To 11 'load the array columns for K row
arrList(j, k) = Resumo.Range("A1:K1").Cells(i, j)
Next j
End If
Next i
ReDim Preserve arrList(1 To 11, 1 To k) 'redim the array to the maximum found occurrences
With frmFormDetalhe
.lstDetalhe.ColumnCount = 11
.lstDetalhe.ColumnHeads = False
.lstDetalhe.ColumnWidths = "20;55;50;50;50;60;55;75;50;50;50"'added the eleventh column width
.lstDetalhe.list = WorksheetFunction.Transpose(arrList)
End With
End Sub

VBA match function with multiple criteria

i am new here and this is my first question, also i dont speak english so my code (variables) is sometimes in dutch.
I have a workbook with multiple sheets (reservations, cottages, validator and schedule). Schedule needs to be filled in with the correct cottage for the reservation.
My question: I want the cottage_id to be returned with the match function. I need the cottage_id (Which is in column A of the cottagesheet), where the class is correct and where the cottage size is correct.
i've tried so much but nothing seems to work
i get error messages like 'type mismatch' and invalid procedure call or argument.
thankyou in advance!
My code:
Dim i As Integer
Dim c As Integer
Dim d As Integer
Dim numrows As Long
Dim laatstekolom As Long
Dim cottagerow As Variant
Dim class As Integer
Dim guests As Variant
Dim cottage_size As Integer
Dim som As Long
Dim somrng As Range
Dim resKlasse As Integer
Dim cottageId As Integer
Dim klasserij As Range
Dim maxpersrij As Range
Dim zoekklasse As Integer
Set roostersheet = Worksheets("rooster")
Set Reservationsheet = Worksheets("reservations")
Set Cottagesheet = Worksheets("cottages")
Set validatorsheet = Worksheets("validator")
Set lookupsheet = Worksheets("lookup")
roostersheet.Cells(1, 1) = "Cottage_id"
'datum uit reservationssheet naar header roostersheet
For i = 1 To 42
roostersheet.Cells(1, 2) = Reservationsheet.Cells(2, 2)
roostersheet.Cells(1, 2 + i) = Reservationsheet.Cells(2, 2) + i
Next i
'cottageid uit cottagesheet naar 1e kolom roostersheet
For i = 1 To 819
roostersheet.Cells(2, 1) = Cottagesheet.Cells(2, 1)
roostersheet.Cells(i + 2, 1) = Cottagesheet.Cells(2, 1) + i
Next i
'fixed in rooster plaatsen
numrows = Reservationsheet.UsedRange.Rows.Count
laatstekolom = roostersheet.UsedRange.Columns.Count
Resnr = validatorsheet.Range("A:A")
For i = 2 To numrows
If Reservationsheet.Cells(i, 16).Value <> 0 Then
cottagerow = Reservationsheet.Cells(i, 16).Value - 1
validatorsheet.Cells(i - 1, 2).Value = Reservationsheet.Cells(i, 16).Value
End If
For d = 2 To laatstekolom
If Reservationsheet.Cells(i, 2) = roostersheet.Cells(1, laatstekolom) Then
Range(roostersheet.Cells(cottagerow, datumkolom), roostersheet.Cells(cottagerow, laatstekolom + Reservationsheet.Cells(i, 3).Value - 1)).Value = Reservationsheet.Cells(i, 1).Value
End If
Next d
Next i
'reserveringen eisen sum = 0
For class = 4 To 1 Step -1
For i = 2 To numrows
guests = Reservationsheet.Cells(i, 4).Value
'juiste cottagesize
If guests = 1 Then
cottage_size = 2
ElseIf guests = 2 Then
cottage_size = 2
ElseIf guests = 3 Then
cottage_size = 4
ElseIf guests = 4 Then
cottage_size = 4
ElseIf guests = 5 Then
cottage_size = 5
ElseIf guests = 6 Then
cottage_size = 6
ElseIf guests = 7 Then
cottage_size = 8
ElseIf guests = 8 Then
cottage_size = 8
Else: cottage_size = 12
End If
zoekklasse = class
lookupsheet.Cells(1, 1).Value = zoekklasse
lookupsheet.Cells(1, 2).Value = cottage_size
If Application.WorksheetFunction.sum(Reservationsheet.Cells(i, 6), Reservationsheet.Cells(i, 15)) = 0 And Reservationsheet.Cells(i, 5).Value = class And Reservationsheet.Cells(i, 4).Value = cottage_size Then
Dim klasseKolom As Variant
Dim SizeKolom As Variant
Dim test As String
Set klasseKolom = Cottagesheet.UsedRange.Columns(3)
Set SizeKolom = Cottagesheet.UsedRange.Columns(2)
' cottageId = Application.Match(1, (klasseKolom = "&zoekklasse&") * (SizeKolom = "&cottage_size&"), 0)
cottageId = Evaluate("MATCH(1, ('lookupsheet'!A1="""&klasseKolom&""") * ('lookupsheet'!A2 = """&SizeKolom&"""), 0)")
'If Application.WorksheetFunction.sum(jjuyiReservationsheet.Cells(i, 6), Reservationsheet.Cells(i, 15)) = 0 And Reservationsheet.Cells(i, 5).Value = class and Then
'validatorsheet.Cells(cottageId, 2).Value = cottagesheet.Cells(i, 1).Value 'invullen in validatorsheet
'Else
'validatorsheet.Cells(i, 2).Value = "x"
End If
'ElseIf som <> 0 Then
Next i
Next class
End Sub
Try the following...
cottageId = Evaluate("MATCH(1,(" & klasseKolom.Address(External:=True) & "=" & zoekklasse & ")*(" & SizeKolom.Address(External:=True) & "=" & cottage_size & "),0)")
Then you can test whether there's a match as follows...
If Not IsError(cottageId) Then
MsgBox cottageId, vbInformation
Else
MsgBox "cottageId not found!", vbExclamation
End If

Sum values from a specific month and user from a large CSV file with 4.5 million lines

I have a huge .csv file with over 4.5 million lines. As this is to big for Excel I need to search the .csv file for any entries from each user and then sum them but the sum needs to be done for a specific month.
Excel
USER Month total value
AAH Febuary 2010 1014
CSV
"USER","DATE_TIME","NUMBER"
"AAH","2010-03-18T17:35:01.000Z","410.0"
"ABH","2011-01-24T09:43:01.000Z","336.0"
"AAH","2010-03-18T19:25:01.000Z","114.0"
"BhC","2012-06-24T03:45:01.000Z","336.0"
"AAH","2010-03-20T19:30:01.000Z","490.0"
Can you help me with a solution ?
You can do it with (tweak to taste) the below. It works on your test data (duplicated to 5.5 million rows or around 230MB it takes about 30 secs on my laptop. No doubt, if performance is vital, it can be improved but it is probably sufficiently fast for your purposes).
Option Explicit
Sub GetData()
Dim fso As Object
Dim fs As Object
Dim results As Collection
Dim arr
Dim i As Long
Dim monthOfInterest As Integer
Dim recordMonth As Date
Dim recordUser As String
Dim recordValue As Variant
Dim recordKey As String
Dim result As Variant
Dim str As String, splitStr() As String
Dim ws As Worksheet
Set fso = CreateObject("Scripting.FileSystemObject")
Set results = New Collection
'enter your path here or use something like FileDialog
Set fs = fso.OpenTextFile("C:\test.csv", ForReading, False, TristateFalse) 'TristateTrue if Unicode
monthOfInterest = 3
If not fs.AtEndOfStream Then fs.SkipLine 'skip past headers at top of CSV
Do While Not fs.AtEndOfStream
splitStr = Split(fs.ReadLine, ",")
If fs.Line Mod 10000 = 0 Then
Application.StatusBar = "Line " & fs.Line
DoEvents
End If
recordMonth = DateSerial( _
Mid(splitStr(1), 2, 4), _
Mid(splitStr(1), 7, 2), 1)
If month(recordMonth) = monthOfInterest Then
recordUser = Mid(splitStr(0), 2, Len(splitStr(0)) - 2)
recordValue = CDec(Mid(splitStr(2), 2, Len(splitStr(2)) - 2))
recordKey = recordUser & "|" & Format(recordMonth, "YYYY-MM")
On Error Resume Next
result = results(recordKey)
If Err.Number <> 5 Then 'key exists
results.Remove recordKey
recordValue = recordValue + result(2)
End If
On Error GoTo 0
results.Add Array(recordUser, recordMonth, recordValue), recordKey
End If
Loop
fs.Close
Application.StatusBar = "Outputting..."
'Process results and dump to worksheet
If results.Count > 0 Then
Set ws = ActiveWorkbook.Worksheets.Add
ReDim arr(0 To results.Count, 0 To 2)
arr(0, 0) = "User"
arr(0, 1) = "Month"
arr(0, 2) = "Total"
For i = 1 To UBound(arr, 1)
arr(i, 0) = results(i)(0)
arr(i, 1) = results(i)(1)
arr(i, 2) = results(i)(2)
Next i
ws.Range(ws.Cells(1, 1), ws.Cells(1 + UBound(arr, 1), 1 + UBound(arr, 2))).Value = arr
End If
Application.StatusBar = ""
End Sub

Resources