Transposing a Range and storing in Variable. Using Variable in Index Match - excel

Hi all I am working on a project and am stuck with transposing the range and storing it in a variable to be used in my index match formula.
The project consists of two worksheets: The inventory worksheet where all of the data is stored, and the ad sheet (where the data will be printed into a table). The variable d is storing the headers of the table on the ad sheet (to be used to match with names in column E of Inventory worksheet). The variable c is the active cell (where the transposed data will be printed).
Essentially I want to get the Range M2:SlastRow on the inventory worksheet, transpose it and then use that as my return range.
The Index match should match the headers from the table (one row above active cell) with the same headers in column E on the Inventory sheet. Then it should print in the active cell column the corresponding data (M:S of the Inventory sheet) and move over to the next column, repeating until the header is empty on the ad sheet.
Below is my code:
Dim ws As Worksheet, lastRow As Long, c As Range, d As Range, ms As Range
Dim f As String
Dim arr As Variant, arr2 As Variant
Set ws = Worksheets("Inventory")
lastRow = Application.Max(ws.Range("E100000").End(xlUp).Row, _
ws.Range("S100000").End(xlUp).Row)
Set c = ActiveCell
Set d = ActiveCell.Offset(-1, 0)
Set ms = Worksheets("Inventory").Range("$M$2:$S$" & lastRow)
arr = Application.Transpose(ms)
arr2 = Application.Transpose(arr)
Do
f = "=IFERROR(INDEX(& arr2 &, MATCH(1, INDEX((& d &=<addrE>),0,1),0)),0)"
f = Replace(f, "<addrE>", "'" & ws.Name & "'!$E$2:$E$" & lastRow)
c.Formula = f
Set c = c.Offset(0, 1)
Set d = d.Offset(0.1)
Loop While Not IsEmpty(d)
Important to note that I am getting an "Application-defined or object-defined error" on the c.Formula = f line

Just transpose the row that matches.
Option Explicit
Sub macro1()
Dim wb As Workbook, ws As Worksheet, wsAd As Worksheet
Dim colE As Range, rowMS As Range, cell As Range
Dim arr As Variant, r As Variant
Dim lastRow As Long
Set wb = ThisWorkbook ' or activeworkbook
Set ws = wb.Worksheets("Inventory")
Set wsAd = wb.Worksheets("Ad")
lastRow = Application.Max(ws.Range("E" & Rows.Count).End(xlUp).Row, _
ws.Range("S" & Rows.Count).End(xlUp).Row)
Set colE = ws.Range("E1:E" & lastRow)
Set rowMS = ws.Range("M1:S1")
Set cell = wsAd.Range("A1")
Do
' match header
r = Application.Match(cell, colE, 0)
If IsError(r) Then
MsgBox "Could not match " & cell.Value, vbExclamation
Else
arr = Application.Transpose(rowMS.Offset(r - 1, 0))
cell.Offset(1, 0).Resize(UBound(arr)).Value2 = arr
End If
Set cell = cell.Offset(0, 1)
Loop While Not IsEmpty(cell)
MsgBox "Done"
End Sub

Related

Excel VBA - For Loop IS taking far far too long to execute

First question ever here, I am the newbiest newbie..
So.. what I am trying to get is:
to find if in sheet1 and sheet2 there are cells with the same value on column E from sheet1 and column F from sheet2. if there are, then copy the value from sheet2 column A row x to sheet2 column P row y.
rows x and y are where the identical values are on each sheet.
this is my code:
Sub ccopiazanrfact()
Dim camion As Worksheet
Dim facturi As Worksheet
Set camion = ThisWorkbook.Sheets("B816RUS")
Set facturi = ThisWorkbook.Sheets("EVIDENTA FACTURI")
Dim nrcomanda As String
Dim nrfactura As String
For a = 2 To facturi.Range("F" & Rows.Count).End(xlUp).Row
nrcomanda = facturi.Range("F" & a).Value
For b = 4 To camion.Range("E" & Rows.Count).End(xlUp).Row
If camion.Range("E" & b).Value = facturi.Range("F" & a).Value Then
camion.Range("P" & b) = facturi.Range("A" & a).Value
Exit For
End If
Next b
Next a
End Sub
I would recommend using arrays to achieve what you want. Nested looping over ranges can make it very slow. Is this what you are trying? (UNTESTED). As I have not tested it, I would recommend making a backup of your data before you test this code.
I have commented the code. But if you still have a question or find an error/bug in the below code then simply ask.
Option Explicit
Sub ccopiazanrfact()
Dim Camion As Worksheet
Dim Facturi As Worksheet
Set Camion = ThisWorkbook.Sheets("B816RUS")
Set Facturi = ThisWorkbook.Sheets("EVIDENTA FACTURI")
'~~> Declare 2 arrays
Dim ArCamion As Variant
Dim ArFacturi As Variant
Dim LRow As Long
'~~> Find last row in Col E of Sheets("B816RUS")
LRow = Camion.Range("E" & Camion.Rows.Count).End(xlUp).Row
'~~> Store Values from E4:P last row in the array. We have taken E:P
'~~> because we are replacing the value in P if match found
ArCamion = Camion.Range("E4:P" & LRow).Value
'~~> Find last row in Col E of Sheets("EVIDENTA FACTURI")
LRow = ArFacturi.Range("F" & ArFacturi.Rows.Count).End(xlUp).Row
'~~> Store Values from A2:F last row in the array. We have taken A:F
'~~> because we are replacing the value in P with A
ArFacturi = Facturi.Range("A2:F" & LRow).Value
Dim i As Long, j As Long
For i = 2 To UBound(ArFacturi)
For j = 4 To UBound(ArCamion)
'~~> Checking if camion.Range("E" & j) = facturi.Range("F" & i)
If ArCamion(j, 1) = ArFacturi(i, 6) Then
'~~> Replacing camion.Range("P" & j) with facturi.Range("A" & i)
ArCamion(j, 12) = ArFacturi(i, 1)
Exit For
End If
Next j
Next i
'~~> Write the array back to the worksheet in one go
Camion.Range("E4:P" & LRow).Resize(UBound(ArCamion), 12).Value = ArCamion
End Sub
in the end, I came up with this and works instantly, get’s all the data filled within a blink of an eye. When I tried it first time I thought i forgot to clear the data before running the code:
Sub FindMatchingValues()
'Declare variables for the worksheets
Dim ws1 As Worksheet
Dim ws2 As Worksheet
'Set the variables to refer to the worksheets
Set ws1 = Worksheets("B816RUS")
Set ws2 = Worksheets("EVIDENTA FACTURI")
'Declare variables for the ranges to compare
Dim rng1 As Range
Dim rng2 As Range
'Set the ranges to the columns to compare
Set rng1 = ws1.Range("E1", ws1.Range("E" & Rows.Count).End(xlUp))
Set rng2 = ws2.Range("F1", ws2.Range("F" & Rows.Count).End(xlUp))
'Loop through each cell in the first range
For Each cell1 In rng1
'Use the Match function to find the matching value in the second range
Dim match As Variant
match = Application.match(cell1.Value, rng2, 0)
'If a match was found, copy the value from column A in the second worksheet to column P in the first worksheet
If Not IsError(match) Then
ws1.Range("P" & cell1.Row).Value = ws2.Range("A" & match).Value
End If
Next cell1
End Sub
Please, test the next code. It should be very fast, using arrays and Find function:
Sub ccopiazaNrfact()
Dim camion As Worksheet, facturi As Worksheet, cellMatch As Range, rngE As Range
Set camion = ThisWorkbook.Sheets("B816RUS")
Set facturi = ThisWorkbook.Sheets("EVIDENTA FACTURI")
Set rngE = camion.Range("E4:E" & camion.Range("E" & camion.rows.count).End(xlUp).row)
Dim a As Long, arrFact, arrP, nrComanda As String
arrP = camion.Range("P1:P" & camion.Range("E" & rows.count).End(xlUp).row).Value
arrFact = facturi.Range("A2:F" & facturi.Range("F" & rows.count).End(xlUp).row).Value
Debug.Print UBound(arrP): Stop
For a = 1 To UBound(arrFact)
nrComanda = arrFact(a, 6)
Set cellMatch = rngE.Find(What:=nrComanda, After:=rngE.cells(1, 1), LookIn:=xlValues, lookAt:=xlWhole)
If Not cellMatch Is Nothing Then
arrP(cellMatch.row, 1) = arrFact(a, 1)
End If
Next a
camion.Range("P1").Resize(UBound(arrP), 1).Value = arrP
MsgBox "Ready..."
End Sub
Please, send some feedback after testing it...
A VBA Lookup: Using Arrays and a Dictionary
Option Explicit
Sub CopiazaNrFact()
Dim wb As Workbook: Set wb = ThisWorkbook
' Write the values from the Source Compare and Value ranges to arrays.
' f - Facturi (Source), c - Compare, v - Value
Dim frg As Range, fcData() As Variant, fvData() As Variant, frCont As Long
With wb.Sheets("EVIDENTA FACTURI")
' Compare
Set frg = .Range("F2", .Cells(.Rows.Count, "F").End(xlUp))
frCont = frg.Rows.Count
fcData = frg.Value ' write to array
' Value
Set frg = frg.EntireRow.Columns("A")
fvData = frg.Value ' write to array
End With
' Write the unique values from the Source Compare array to the 'keys',
' and their associated values from the Source Values array to the 'items'
' of a dictionary.
Dim fDict As Object: Set fDict = CreateObject("Scripting.Dictionary")
fDict.CompareMode = vbTextCompare
Dim fr As Long, NrFacturi As String
For fr = 1 To frCont
NrFacturi = CStr(fcData(fr, 1))
If Len(NrFacturi) > 0 Then ' exclude blanks
fDict(NrFacturi) = fvData(fr, 1)
End If
Next fr
' Write the values from the Destination Compare range to an array
' and define the resulting same-sized Destination Value array.
' c - Camion (Destination), c - Compare, v - Value
Dim crg As Range, ccData() As Variant, cvData() As Variant, crCont As Long
With wb.Sheets("B816RUS")
' Compare
Set crg = .Range("E4", .Cells(.Rows.Count, "E").End(xlUp))
crCont = crg.Rows.Count
ccData = crg.Value ' write to array
' Value
Set crg = crg.EntireRow.Columns("P")
ReDim cvData(1 To crCont, 1 To 1) ' define
End With
' For each value in the Destination Compare array, attempt to find
' a match in the 'keys' of the dictionary, and write the associated 'item'
' to the same row of the Destination Value array.
Dim cr As Long, NrCamion As String
For cr = 1 To crCont
NrCamion = CStr(ccData(cr, 1))
If fDict.Exists(NrCamion) Then cvData(cr, 1) = fDict(NrCamion)
Next cr
' Write the values from the Destination Value array
' to the Destination Value range.
crg.Value = cvData
End Sub

Count If in a User Defined range

I want a CountIf Formula in which JV_Rng (workbook 1 range) is the range and 9th column (and r row) of GL_Sheet (workbook 2) is the criteria. Upon running the code I receive error 1004 (application or object defined error)
The error is possibly due to my inability to include the JV_Rng in the Count If Formula. The whole code is as follows
'Filtering Range
Dim GL_Code As Single, GL_Rng As range, GL_LR As Long
Dim GL_Sheet As Worksheet
Set GL_Sheet = Workbooks("Deodar GL activities.xlsx").Worksheets("Sheet1")
GL_LR = GL_Sheet.range("B" & Rows.Count).End(xlUp).Row
GL_Code = Application.InputBox(Prompt:="Enter GL code", Title:="Generate GL", Type:=1)
Set GL_Rng = GL_Sheet.range("A4:R" & GL_LR).CurrentRegion.Offset(3, 0)
GL_Rng.AutoFilter Field:=6, Criteria1:=GL_Code
'Shift Rng into new sheet
Dim Tgt_Book As Workbook
Set Tgt_Book = Workbooks.Add
Dim tgt As Worksheet: Set tgt = Tgt_Book.Worksheets.Add
......
'Shift JV of that Code
Dim r As Long, JV_Rng As range
Set JV_Rng = tgt.range("J6:R" & GL_LR).Offset(5, 0)
For r = 5 To GL_LR
GL_Sheet.range("S" & r).Formula = "=COUNTIF(tgt.Range(JV_rng),R[r]C[9])"
Next r
The code is working successfully except for this part
GL_Sheet.range("S" & r).Formula = "=COUNTIF(tgt.Range(JV_rng),R[r]C[9])"
Please, replace:
For r = 5 To GL_LR
GL_Sheet.range("S" & r).Formula = "=COUNTIF(tgt.Range(JV_rng),R[r]C[9])"
Next r
with
tgt.range("S5:S" & GL_LR).Formula = "=COUNTIF(" & JV_Rng.Address(external:=True) & ", I5)"
No iteration needed.
In above code line I tried to convert your R[r]C[9] in A1 notation. Would you like counting I:I column cells values in S:S column? Otherwise, your formula was not targeting the correct ranges...

How do i copy and paste data to worksheets that i created in VBA using for loop?

Im trying to copy and paste my data and assign them into different worksheets.For example, if column F is martin 1, the entire row that has martin1 will be paste to worksheets("Index1"). Same thing for Charlie 1 and it will be paste to worksheets("Index2"). However, I faced with a object defined error here as shown in my code below. Any ideas how to solve it?
Sub SaveRangewithConsecutiveDuplicateValuestoNewSheet()
'Define all variables
Dim wb As Workbook, ws As Worksheet, sCel As Range, rwNbr As Long
Set wb = ThisWorkbook 'Set workbook variable
Set ws = wb.Worksheets("Sheet1") 'set worksheet variable using workbook variable
Set sCel = ws.Cells(1, 6) 'Set the first start cell variable to test for duplicate values
Dim i As Integer
Dim site_i As Worksheet
For i = 1 To 3
Set site_i = Sheets.Add(after:=Sheets(Worksheets.count))
site_i.Name = "Index" & CStr(i)
Next i
Application.DisplayAlerts = False
For rwNbr = 2 To ws.Cells(ws.Rows.count, 6).End(xlUp).Offset(1).Row Step 1 'Loop
If ws.Cells(rwNbr, 6).Value = "Martin1" Then
ws.Range(sCel, ws.Cells(rwNbr, 6)).EntireRow.Copy Destination:=Sheets("Index1").Range("A1")
ElseIf ws.Cells(rwNbr, 6).Value = "Charlie1" Then
ws.Range(sCel, ws.Cells(rwNbr - ws.UsedRange.Rows.count, 6)).EntireRow.CopyDestination:=Sheets("Index2").Range("A1") '<----application defined or object defined error here
End If
Next rwNbr
Application.DisplayAlerts = True
End Sub
This is the link to my worksheet. https://www.dropbox.com/home?preview=Sample+-+Copy.xlsm
The final output should look something like this...
If your raw data does not have a header row then I would use a loop to gather up your target cells and copy them accordingly.
You will need to update your 3 target values inside Arr to Charlie1, Martin1, etc.
Macro Steps
Loop through each name in Arr
Loop through each row in Sheet1
Add target row to a Union (collection of cells)
Copy the Union to the target sheet where target Sheet Index # = Arr position + 1
Sub Filt()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim cs As Worksheet
Dim Arr: Arr = Array("Value1", "Value2", "Value3")
Dim x As Long, Target As Long, i As Long
Dim CopyMe As Range
'Create 3 Sheets, move them to the end, rename
For x = 1 To 3
Set cs = ThisWorkbook.Sheets.Add(After:=Sheets(ThisWorkbook.Sheets.Count))
cs.Name = "Index" & x
Next x
lr = ws.Range("F" & ws.Rows.Count).End(xlUp).Row
'Loop through each name in array
For Target = LBound(Arr) To UBound(Arr)
'Loop through each row
For i = 1 To lr
'Create Union of target rows
If ws.Range("F" & i) = Arr(Target) Then
If Not CopyMe Is Nothing Then
Set CopyMe = Union(CopyMe, ws.Range("F" & i))
Else
Set CopyMe = ws.Range("F" & i)
End If
End If
Next i
'Copy the Union to Target Sheet
If Not CopyMe Is Nothing Then
CopyMe.EntireRow.Copy Destination:=ThisWorkbook.Sheets("Index" & Target + 1).Range("A1")
Set CopyMe = Nothing
End If
Next Target
End Sub
Tested and working as expected on my end, however....
If you had headers this would be much easier with a copy/paste. If you run the same macro on same book twice this will break for many reasons such as having duplicated sheet names, breaking the relationship between Sheet Index # = Arr Position + 1, etc...

Sumif Returning Same Value

I got below table that I need to fill with data based on current month (Worksheet "PR"):
An example of the raw data looks like (Worksheet "CSV Data PR"):
I have two issues:
SumIF only works for the first region, all the others take the same data. As example, correct data shows below Feb.
For some reason it pulls the formula down all the way..., whilst it should stop at Western Europe. I am not sure why that is the case.
Based on the following piece of code:
Sub TableDataTest()
Dim rngHdrFound, rngHdrFound2, findrng, USDRng, RegionRNG, rngHeaders, RngHeadersOutPut As Range
Dim x, y As Worksheet
Dim ThisMonth As Date
Dim index As Variant
Application.ScreenUpdating = False
'Set Worksheets
Set x = ThisWorkbook.Sheets("CSV Data PR")
Set y = ThisWorkbook.Sheets("PR")
index = y.Range("D8")
ThisMonth = Format(Date, "MM/YYYY")
'Set HeaderRow
Const ROW_HEADERS As Integer = 1
Set rngHeaders = Intersect(Worksheets("CSV Data PR").UsedRange, Worksheets("CSV Data PR").Rows(ROW_HEADERS))
Set RngHeadersOutPut = y.Range("6:6")
Set rngHdrFound = rngHeaders.Find("In USD")
Set rngHdrFound2 = rngHeaders.Find("Region")
Set findrng = RngHeadersOutPut.Find(What:=ThisMonth, LookIn:=xlFormulas, lookat:=xlWhole)
Set USDRng = Range(rngHdrFound.Offset(1), rngHdrFound.End(xlDown))
Set RegionRNG = Range(rngHdrFound2.Offset(1), rngHdrFound2.End(xlDown))
'Find CurrentMonth + Range
With y
If findrng Is Nothing Then
MsgBox "Error, unable to match " & ThisMonth & " in the specified range", vbCritical
Exit Sub
Else
findrng.Offset(2, 0).Resize(Selection.Rows.Count + 8).Value = Application.WorksheetFunction.SumIf(RegionRNG, "=" & index, USDRng)
End If
End With
Application.ScreenUpdating = True
End Sub
You could try this:
Option Explicit
Sub TableDataTest()
Dim ws As Worksheet, wsData As Worksheet, MonthCol As Integer, ThisMonth As Date, C As Range, _
x As Integer, y As Integer
x = 2 'Number of the column with the region
y = 3 'Number of the column with the data to sum
With ThisWorkbook
Set ws = .Sheets("PR")
Set wsData = .Sheets("CSV Data PR")
End With
ThisMonth = Format(wsData.Range("C2"), "MM/YYYY")
With ws
MonthCol = .Cells.Find(ThisMonth, LookIn:=xlFormulas, lookat:=xlWhole).Column
For Each C In .Range(.Cells(3, Col), .Cells(11, Col))
C = Application.SumIf(wsData.Columns(x), .Cells(C.Row, 1), wsData.Columns(y))
Next C
End With
End Sub
You only need to find the column where the month is on the table, and then hardcode the rows you wanna work in because as for I can see, they are always the same and unlikely to grow.
PS: I'm assuming the table starts on row 3 and column A, otherwise change the starting row 3 on the For Each C range and the criteria inside the sumif taking column 1.

Copy rows to new sheet if condition is met (with VBA)

I'm trying to copy rows from master table sheet to different sheets based on the value of the cell in the column:
The column "AL" contains several values (validation list) for example dog, cat, giraffe, I'd like to automatically open new sheet for every value and copy the relevant rows to the new sheet. (the new sheets must have the name of the value).
In addition when a new data is added, I need the new rows to be added to the correct sheet.
Sub Copy_Data()
Dim r As Range, LastRow As Long, ws As Worksheet
Dim v As Variant, s As String, LastRow1 As Long
Dim src As Worksheet
Set src = Sheets("Sheet1")
LastRow = src.Cells(Cells.Rows.Count, "AL").End(xlUp).Row
'Change these to your strings to copy
s = "dog,cat,fish,giraffe"
v = Split(s, ",")
For Each r In src.Range("AL1:AL" & LastRow)
If Not IsError(Application.Match(CStr(r.Value), v, 0)) Then
On Error Resume Next
Set ws = Sheets(CStr(r.Value))
On Error GoTo 0
If ws Is Nothing Then
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = CStr(r.Value)
LastRow1 = Sheets(CStr(r.Value)).Cells(Cells.Rows.Count, "AL").End(xlUp).Row
src.Rows(r.Row).Copy Sheets(CStr(r.Value)).Cells(LastRow1 + 1, 1)
Set ws = Nothing
Else
LastRow1 = Sheets(CStr(r.Value)).Cells(Cells.Rows.Count, "Al").End(xlUp).Row
src.Rows(r.Row).Copy Sheets(CStr(r.Value)).Cells(LastRow1 + 1, 1)
Set ws = Nothing
End If
End If
Next r
End Sub

Resources