Checking and adding values - excel

I am trying to:
open an import file
check for identical values of import file in target file in several columns
if matched, update one cell in target file
if not matched, add another row
This is my code so far (I didn't clean it yet):
Public Declare PtrSafe Function SetCurrentDirectoryA Lib "kernel32" (ByVal lpPathName As String) As Long
Sub Import_Macro()
Dim wbData As Workbook
Dim wsData As Worksheet
Dim rngData As Range
Set rngData = Selection
Set wbData = Workbooks(rngData.Parent.Parent.Name)
Set wsData = wbData.Sheets("Fehleranalyse Daten")
'DATA IMPORT
Dim wbImport As Workbook
Dim wsImport As Worksheet
Dim Lastrow_wsData As String
Dim Lastrow_wsData_neu As String
Lastrow_wsData = wsData.Range("A:A").Columns(1).Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
'Import from file
MyPath = Application.ActiveWorkbook.Path
SetCurrentDirectoryA MyPath
strFileToOpen = Application.GetOpenFilename _
(Title:="Bitte Datei für Fehler-Reporting auswählen", _
FileFilter:="Excel Files *.xls*; *.csv (*.xls*; *.csv),")
'Defining names for Import
Dim rngImport As Range
Set rngImport = Selection
Set wbImport = Workbooks(rngImport.Parent.Parent.Name)
Set wsImport = wbImport.Sheets("Sheet1")
Dim Lastrow_Import As Long
Lastrow_Import = wsImport.Range("A:A").Columns(1).Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Dim AnmelderImport As Long
Dim AnmelderData As Long
Dim AbteilungImport As Long
Dim AbteilungData As Long
Dim VNrImport As Long
Dim VNrData As Long
Dim AuftragsNrImport As Long
Dim AuftragsNrData As Long
Dim VersuchImport As Long
Dim VersuchData As Long
Dim iCol As Long
Dim colnameData As Variant
Dim colnumImport As Variant
Dim lrData As Long
Dim lcData As Long
Dim lcImport As Long
Dim lrs As Long
Dim r As Long
Dim c As Long
Dim iSOP As Long
Dim j As Long
Dim i As Range
Dim k As Range
Dim n As Long
Dim Check As Variant
Dim arr As Variant
'Creating several array I need to either check for matching or copying
VersuchImport = Application.WorksheetFunction.Match("VERSUCH", wsImport.Range("11:11"), 0) 'Ermittlung der Spalte für Versuch
VersuchData = Application.WorksheetFunction.Match("VERSUCH", wsData.Range("1:1"), 0)
AuftragsNrImport = Application.WorksheetFunction.Match("AUFTRAGSNUMMER", wsImport.Range("11:11"), 0) 'Ermittlung der Spalte für Auftragsnr.
AuftragsNrData = Application.WorksheetFunction.Match("AUFTRAGSNUMMER", wsData.Range("1:1"), 0)
TestzweckImport = Application.WorksheetFunction.Match("TESTZWECK", wsImport.Range("11:11"), 0) 'Ermittlung der Spalte für Testzweck
TestzweckData = Application.WorksheetFunction.Match("TESTZWECK", wsData.Range("1:1"), 0)
StatusImport = Application.WorksheetFunction.Match("AUFTRAGSSTATUS", wsImport.Range("11:11"), 0) 'Ermittlung der Spalte für Status
StatusData = Application.WorksheetFunction.Match("AUFTRAGSSTATUS", wsData.Range("1:1"), 0)
Debug.Print "VersuchImport = " & VersuchImport
Debug.Print "VersuchData = " & VersuchData
Debug.Print "AuftragsNrImport = " & AuftragsNrImport
Debug.Print "AuftragsNrData = " & AuftragsNrData
Debug.Print "TestzweckImport = " & TestzweckImport
Debug.Print "TestzweckData = " & TestzweckData
With wsImport
Check = .Range(.Cells(1, VersuchImport).Address, .Cells(Lastrow_Import, VersuchImport).End(xlUp).Address).Value2 & .Range(.Cells(1, AuftragsNrImport).Address, .Cells(Lastrow_Import, Auftragsnr).End(xlUp).Address).Value2
End With
'I'm creating another array with column names to be copied (bayed on target file)
With wsData
lrData = wsData.Range("A:A").Columns(1).Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
lcData = Application.WorksheetFunction.Match("AUFTRAGSSTATUS", .Range("1:1"), 0)
colnameData = Application.Transpose(.Range(.Cells(1, 1), .Cells(1, lcData)).Value)
End With
'The corresponding array in the source file
With wsImport
lcImport = Application.WorksheetFunction.Match("SORTIERUNG", .Range("11:11"), 0)
ReDim colnumImport(lcImport, 1)
For iCol = 1 To lcImport
On Error Resume Next
colnumImport(iCol, 1) = .Rows(11).Find(What:=colnameData(iCol, 1), LookIn:=xlValues, lookat:=xlWhole, SearchOrder:=xlByColumns, SearchDirection:=xlNext, MatchCase:=False).Column
Next iCol
End With
'This section copies all relevant columns and rows if not matched (not cleaned up though)
Dim lcellData As Range
Dim cellAuftragsNrImport As Range
Dim RngAuftragsNrImport As Variant
Dim RngAuftragsNrData As Variant
Dim Status As Long
Dim cellVersuchImport As Range
Dim RngVersuchImport As Variant
Dim RngVersuchData As Variant
Dim cellStatusImport As Range
Dim RngStatusImport As Variant
Dim RngStatusData As Variant
Dim cellTestzweckImport As Range
Dim RngTestzweckImport As Variant
Dim RngTestzweckData As Variant
Dim iZweck As Long
With wsImport
RngAuftragsNrImport = .Range(.Cells(12, AuftragsNrImport).Address, .Cells(Lastrow_Import, AuftragsNrImport).Address).Value2
RngTestzweckImport = .Range(.Cells(12, TestzweckImport).Address, .Cells(Lastrow_Import, TestzweckImport).Address).Value2
RngVersuchImport = .Range(.Cells(12, VersuchImport).Address, .Cells(Lastrow_Import, VersuchImport).Address).Value2
RngStatusImport = .Range(.Cells(12, StatusImport).Address, .Cells(Lastrow_Import, StatusImport).Address).Value2
End With
With wsData
RngAuftragsNrData = .Range(.Cells(3, AuftragsNrData).Address, .Cells(Lastrow_wsData, AuftragsNrData).Address).Value2
RngVersuchData = .Range(.Cells(3, VersuchData).Address, .Cells(Lastrow_wsData, VersuchData).Address).Value2
RngStatusNrData = .Range(.Cells(3, StatusData).Address, .Cells(Lastrow_wsData, StatusData).Address).Value2
RngTestzweckNrData = .Range(.Cells(3, TestzweckData).Address, .Cells(Lastrow_wsData, TestzweckData).Address).Value2
End With
ReDim arr(0)
For iZweck = LBound(RngTestzweckImport, 1) To UBound(RngTestzweckImport, 1)
If RngTestzweckImport(iZweck, 1) = "Entwicklungstest" Then
ReDim Preserve arr(j)
arr(j) = iZweck + 11
j = j + 1
End If
Next iZweck
For Each cellAuftragsNrImport In RngAuftragsNrImport
With wsData.Cells 'RngAuftragsNrData.Cells
Set i = .Find(cellAuftragsNrImport, LookIn:=xlValues, lookat:=xlWhole)
If Not i Is Nothing Then
k = i.Row
Status = .Cells(k, StatusData).Value
If cellStatusImport.Value <> Status Then
cellStatusImport.Copy Destination:=wsData.Cells(i.Row, StatusData)
End If
Else
With wsData
lrData = Lastrow_wsData
For r = LBound(arr) To UBound(arr)
lrData = .Cells(.Rows.Count, 1).End(xlUp).Row
For c = 1 To lcData
.Cells(lrData + 1, c).Value = wsImport.Cells(arr(r), colnumImport(c, 1)).Value
Next c
Next r
End With
End If
End With
Next
End Sub
All names ending with "Import" are from the source file. All names ending with "Data" are for the target file.
I'm trying to:
Check if items of the source file are already part of the target file. That applies only to lines that contain the value "Entwicklungstest" (see arr).
The criteria to be checked are: AuftragsNr (Order ID), Testzweck and Date.
So far my macro only checks for AuftragsNr. Even for that single criteria, my macro doesn't work.
So basically, if the three criteria from above are not met in the target file, a new line should be added. If the criteria are met, the column "Status" must be updated with the value from the source file.
When executing the macro, all it does is add all lines with "Entwicklungstest" after the last row of the target file.

Related

Offset one cell down doesn't work for some reason

I would like to have up to 6 records which will be based on the answers located in the row beneath.
My code so far looks like this:
Sub Copy_Data_Correctly(ByRef datSource As Worksheet, datTarget As Worksheet)
'QUESTION 1
Const TM_PM As String = "*PM is required*"
Dim que1 As Range
Dim ans1 As Range
Set que1 = Sheets("Sheet1").Range("A1:A100").Find(What:=TM_PM, _
Lookat:=xlPart, LookIn:=xlValues)
If Not que1 Is Nothing Then
'MsgBox ("The question about PM or TM wasn't found")
End If
Set ans1 = que1.Offset(1)
'QUESTION 2
Const LID_LIFTED As String = "*be lifted*"
Dim que2 As Range
Dim ans2 As Range
Set que2 = Sheets("Sheet1").Range("A1:A100").Find(What:=LID_LIFTED, _
Lookat:=xlPart, LookIn:=xlValues)
If Not que2 Is Nothing Then
End If
Set ans2 = que2.Offset(1)
'EXTRACTING THE DATA
Dim lrow1 As Long, lrow2 As Long, lrow3 As Long, lrow4 As Long, lrow5 As Long, lrow6 As Long
lrow1 = datTarget.Range("E" & datTarget.Rows.Count).End(xlUp).Row + 1
lrow2 = datTarget.Range("F" & datTarget.Rows.Count).End(xlUp).Row + 1
que1.Copy
datTarget.Range("E1").PasteSpecial xlPasteValuesAndNumberFormats
ans1.Copy
datTarget.Range("E" & lrow1).PasteSpecial xlPasteValuesAndNumberFormats
que2.Copy
datTarget.Range("F1").PasteSpecial xlPasteValuesAndNumberFormats
ans2.Copy
datTarget.Range("F" & lrow2).PasteSpecial xlPasteValuesAndNumberFormats
End Sub
If I have the second question & answer standalone, then it works. Unfortunately after adding the Q&A1 the error:
Object variable or with variable not set
occurs at the line:
Set ans1 = que1.Offset(1)
why the code behaves like that?
Copy Conditionally
Using the Find method, it will attempt to find each string, containing wild characters, from a list in range A1:A100 of one worksheet (source), then take this matching value (which is different (no wild characters)), and by using Application.Match, it will attempt to find a match in the headers of another worksheet (destination). If a match is found, then the result, the value of the cell below the previously found cell, will be written into the first available row. If no match is found, a new header will be created from the value of the found cell, and the value below the found cell will be written into the first available row.
Option Explicit
Sub CopyData( _
ByVal wsSource As Worksheet, _
ByVal wsDestination As Worksheet)
' Add more: comma separated, no spaces
Const sCriteriaList As String = "*PM is required,*be lifted*"
Const sCriteriaListDelimiter As String = ","
Const sAddress As String = "A1:A100"
Const dfhCellAddress As String = "E1"
Dim sCriteria() As String
sCriteria = Split(sCriteriaList, sCriteriaListDelimiter)
Dim srg As Range: Set srg = wsSource.Range(sAddress)
Dim dfhCell As Range: Set dfhCell = wsDestination.Range(dfhCellAddress)
Dim dfRow As Long: dfRow = dfhCell.Row
Dim dfCol As Long: dfCol = dfhCell.Column
Dim dlhCell As Range: Set dlhCell = _
wsDestination.Cells(dfRow, wsDestination.Columns.Count).End(xlToLeft)
Dim dhrg As Range
If dlhCell.Column < dfCol Then
Set dhrg = dfhCell
Else
Set dhrg = wsDestination.Range(dfhCell, dlhCell)
End If
Dim dlCol As Long: dlCol = dhrg.Columns(dhrg.Columns.Count).Column
Dim dlCell As Range
Set dlCell = _
wsDestination.Cells.Find("*", , xlFormulas, , xlByRows, xlPrevious)
Dim dRow As Long
If Not dlCell Is Nothing Then
If dlCell.Row <= dfhCell.Row Then
dRow = dfhCell.Row + 1
Else
dRow = dlCell.Row + 1
End If
Else
dRow = dfhCell.Row + 1
End If
Dim sCell As Range
Dim sQuestion As String
Dim sAnswer As String
Dim drrg As Range
Dim dhIndex As Variant
Dim n As Long
For n = 0 To UBound(sCriteria)
Set sCell = srg.Find( _
sCriteria(n), srg.Cells(srg.Cells.Count), xlValues, xlWhole)
If Not sCell Is Nothing Then
sQuestion = sCell.Value
sAnswer = CStr(sCell.Offset(1).Value)
dhIndex = Application.Match(sQuestion, dhrg, 0)
If IsNumeric(dhIndex) Then
wsDestination.Cells(dRow, dhIndex + dfCol - 1).Value = sAnswer
Else
Set dhrg = dhrg.Resize(, dhrg.Columns.Count + 1)
dlCol = dlCol + 1
wsDestination.Cells(dfRow, dlCol).Value = sQuestion
wsDestination.Cells(dRow, dlCol).Value = sAnswer
End If
End If
Next n
End Sub

append value to list within loop

I am running through a column and storing the value for each row in a dictionary.
if the value does not exists i want to add a cell value on that row to an array/list. In the end i want a sum of all the values in the array.
How do i append the values to an array and sum the values in the array? I hope someone can help
Code
Const NETSCONT_SHT3 = "D"
Const NETSCONT_SHT4 = "I"
Const NETSEXP_SHT4 = "H"
Const MEMBER_SHT4 = "G"
Dim wb As Workbook, wbNew As Workbook
Dim ws1 As Worksheet, ws3 As Worksheet, ws4 As Worksheet
Dim iRow As Long, iLastRow, iTargetRow As Long, iCopyRow As Long, NbCont_SHT3 As Long, AmCont_SHT3 As Double
Dim NbCont_SHT4 As Long, AmCont_SHT4 As Double, NbResults As Integer, AmResult As Double, pct_change As Double
Dim msg As String, i As Integer, j As Integer
Dim count As Long, countWB As Integer
Dim WkSht_Src As Worksheet
Dim WkBk_Dest As Workbook
Dim WkSht_Dest As Worksheet
Dim Rng As Range
Dim r As Long
Dim d As Long, dE As Long
Set wb = ThisWorkbook
Set ws1 = wb.Sheets("BrokerSelect")
Set ws3 = wb.Sheets("ContributionSplitReport")
Set ws4 = wb.Sheets("ContributionExceptionReport")
Dim dict As Object, dictEXP As Object, dictRESULTP As Object, dictRESULTN As Object, dictMEMBER As Object, sKey As Double, ar As Variant
Dim sEXP As Double, sRESP As Double, sRESN As Double, sMEMBER As Integer, arEXP As Variant, arRESP As Variant, arRESN As Variant, arMEMBER As Variant
Set dict = CreateObject("Scripting.Dictionary")
Set dictEXP = CreateObject("Scripting.Dictionary")
Set dictRESULTP = CreateObject("Scripting.Dictionary")
Set dictRESULTN = CreateObject("Scripting.Dictionary")
Set dictMEMBER = CreateObject("Scripting.Dictionary")
iLastRow = ws4.Cells(Rows.count, MEMBER_SHT4).End(xlUp).Row
For iRow = 18 To iLastRow
sMEMBER = ws4.Cells(iRow, MEMBER_SHT4) ' column "G"
sKey = ws4.Cells(iRow, NETSCONT_SHT4) ' column "I"
sEXP = ws4.Cells(iRow, NETSEXP_SHT4) ' column "H"
If dictMEMBER.exists(sMEMBER) Then
dictMEMBER(sMEMBER) = dictMEMBER(sMEMBER) & ";" & iRow
Else
dictMEMBER(sMEMBER) = iRow
If sKey <> "0" Then
pct_change = (sKey - sEXP) / sKey
If pct_change > 0 Then
dictRESULTP.Add d, pct_change: d = d + 1
ElseIf pct_change < 0 Then
dictRESULTN.Add dE, pct_change: dE = dE + 1
End If
End If
'If dictMEMBER(sMEMBER) does not exist I want to append the cell value (irow, i) into an array.
'In the end i want to sum the value of the array
End If
next
I'm not entirely clear about what you wish to achieve but the code below will do most of it. Please try it.
Sub Benchmark()
' This proc needs a reference to 'Miscrosoft Scripting Runtime'
' If you use late binding VBA will do without the reference but you
' won't have the benefit of Intellisense drop-downs while programming.
' Checkmark: Tools > References > Microsoft Scripting Runtime'
Const ConExMember = "G"
Const ConExExp = "H"
Const ConExAct = "I"
Dim Wb As Workbook
Dim WsConEx As Worksheet
Dim Dict As Scripting.Dictionary
Dim Member As String
Dim Expected As Double, Actual As Double
Dim ChangePct As Double
Dim Rl As Long ' last row
Dim R As Long ' rows loop counter
Dim Tmp As Variant
Dim Msg As String, Count(2) As Integer
Set Wb = ThisWorkbook
Set WsConEx = Wb.Sheets("ContributionExceptionReport")
Set Dict = CreateObject("Scripting.Dictionary")
' pct change in expected and actual cont
With WsConEx
Rl = .Cells(.Rows.Count, ConExMember).End(xlUp).Row
For R = 18 To Rl
Member = .Cells(R, ConExMember).Value
Actual = Val(.Cells(R, ConExAct).Value)
Expected = Val(.Cells(R, ConExExp).Value)
On Error Resume Next ' if Actual = 0
ChangePct = (Actual - Expected) / Actual
If Err.Number Then ChangePct = 0
On Error GoTo 0
If Not Dict.Exists(Member) Then
Dict.Add Member, ChangePct
End If
Next R
End With
ChangePct = 0
For Each Tmp In Dict.Keys
ChangePct = ChangePct + Dict(Tmp)
R = Sgn(Dict(Tmp)) + 1
Count(R) = Count(R) + 1
Next Tmp
Msg = "Members: " & Dict.Count & vbCr & _
"Increases: " & Count(2) & vbCr & _
"Decreases: " & Count(1) & vbCr & _
"Unchanged: " & Count(0) & vbCr & _
"Change % : " & Round(ChangePct * 100, 2) & "%"
MsgBox Msg, vbInformation, "Summary"
End Sub
The code will loop through all your members in what was your Ws4. It will skip over duplicates. Unique members will be added to a dictionary with their names (or perhaps ID numbers) as Key and the percentage of change as Item. The result will be one dictionary with all unique names and all the changes.
In the second half of the code this dictionary is examined. Changes are sorted into positive, negative and unchanged and counted for each category. The aggregate change is calculated and the members counted. All of that goes into a message box.
The important change I made is to create pairs of data, with the member ID as key and the change as related information. This data can be evaluated easily, with very few lines of code, whichever way you want.
I update the code as following hoping it would be helpful to you:
Sub AddAndSumMissingDictionary()
'Constants
Const NETSCONT_SHT3 = "D"
Const NETSEXP_SHT4 = "H"
Const NETSCONT_SHT4 = "I"
Const MEMBER_SHT4 = "G"
'ArrayColumns
Const cTotalExpected = 0
Const cTotalNets = 1
Const cTotalNetSplitAVC = 2
'Workbooks & Worksheets
Dim wb As Workbook, wbNew As Workbook
Dim ws1 As Worksheet, ws3 As Worksheet, ws4 As Worksheet
Dim WkSht_Src As Worksheet
Dim WkBk_Dest As Workbook
Dim WkSht_Dest As Worksheet
'Array you Requested
Dim ArrMissingDictionary() As Double
Dim lMissingDictCount As Long
'Iteration Rows & Ranges
Dim iRow As Long, iLastRow As Long, iTargetRow As Long, iCopyRow As Long, NbCont_SHT3 As Long, AmCont_SHT3 As Double
Dim NbCont_SHT4 As Long, AmCont_SHT4 As Double, NbResults As Integer, AmResult As Double, pct_change As Double
Dim msg As String, i As Integer, j As Integer
Dim count As Long, countWB As Integer
Dim Rng As Range
Dim r As Long
Dim d As Long, dE As Long
'Initializing Variables
Set wb = ThisWorkbook
Set ws1 = wb.Sheets("BrokerSelect")
Set ws3 = wb.Sheets("ContributionSplitReport")
Set ws4 = wb.Sheets("ContributionExceptionReport")
Dim dict As Object, dictEXP As Object, dictRESULTP As Object, dictRESULTN As Object, dictMEMBER As Object, sKey As Double, ar As Variant
Dim sEXP As Double, sRESP As Double, sRESN As Double, sMEMBER As Integer, arEXP As Variant, arRESP As Variant, arRESN As Variant, arMEMBER As Variant
'Initializing Dictionaries
Set dict = CreateObject("Scripting.Dictionary")
Set dictEXP = CreateObject("Scripting.Dictionary")
Set dictRESULTP = CreateObject("Scripting.Dictionary")
Set dictRESULTN = CreateObject("Scripting.Dictionary")
Set dictMEMBER = CreateObject("Scripting.Dictionary")
'Set Missing lMissingDictCount to 0
lMissingDictCount = 0
'Get the Last Row
iLastRow = ws4.Cells(Rows.count, MEMBER_SHT4).End(xlUp).Row
'Iteration Process
For iRow = 18 To iLastRow
sMEMBER = ws4.Cells(iRow, MEMBER_SHT4) ' column "G"
sKey = ws4.Cells(iRow, NETSCONT_SHT4) ' column "I"
sEXP = ws4.Cells(iRow, NETSEXP_SHT4) ' column "H"
'Checking Existance of Dictionary Entry
If dictMEMBER.exists(sMEMBER) Then
'I think this should be like this
dictMEMBER.Key(sMEMBER) = dictMEMBER(sMEMBER) & ";" & iRow 'dictMEMBER(sMEMBER) = dictMEMBER(sMEMBER) & ";" & iRow
Else
dictMEMBER.Key(sMEMBER) = iRow 'dictMEMBER(sMEMBER) = iRow
If sKey <> "0" Then
pct_change = (sKey - sEXP) / sKey
If pct_change > 0 Then
dictRESULTP.Add d, pct_change: d = d + 1
ElseIf pct_change < 0 Then
dictRESULTN.Add dE, pct_change: dE = dE + 1
End If
End If
'Increment lMissingDictCount
lMissingDictCount = lMissingDictCount + 1 'UBound(ArrMissingDictionary, 1) + 1
'Adding the Array:
ReDim Preserve ArrMissingDictionary(2, lMissingDictCount) 'Increasing the Array Row while keeping its content
ArrMissingDictionary(cTotalExpected, lMissingDictCount) = ws4.Cells(iRow, NETSEXP_SHT4)
ArrMissingDictionary(cTotalNets, lMissingDictCount) = ws4.Cells(iRow, NETSCONT_SHT4)
ArrMissingDictionary(cTotalNetSplitAVC, lMissingDictCount) = ws4.Cells(iRow, MEMBER_SHT4)
'If dictMEMBER(sMEMBER) does not exist I want to append the cell value (irow, i) into an array.
End If
Next iRow
'In the end i want to sum the value of the array
'I'm reusing the iRow again
Dim dTotalExpected As Double, dTotalNets As Double, dTotalNetSplitAVC As Double
For iRow = LBound(ArrMissingDictionary, 1) To UBound(ArrMissingDictionary, 1)
dTotalExpected = dTotalExpected + ArrMissingDictionary(cTotalExpected, iRow) 'Sum Missing on Col "H"
dTotalNets = dTotalNets + ArrMissingDictionary(cTotalNets, iRow) 'Sum Missing on Col "I"
dTotalNetSplitAVC = dTotalNetSplitAVC + ArrMissingDictionary(cTotalNetSplitAVC, iRow) 'Sum Missing on Col "G"
Next iRow
'You can affect the dTotalExpected, dTotalNets and dTotalNetSplitAVC for your purpose
End Sub
Hopefully, this will solve your issue

Moving columns containg "Total" at the end of the pivot(after paste special) if the cells of second row contain the word "Total"

' If the cells of second row contain the word "Total" ,I want to copy paste the entire column of that cell to the end of the table.The following code gives no output. Can someone please help me identify my mistake?
enter image description here
Dim PRTSLastRow As Long
Dim PRTSLastCol As Long
Dim ColLtr As String
Dim LastColLtr As String
Dim Total As String
Dim j as Integer
W = ActiveWorkbook.Name
PRTSLastCol = Worksheets("PRTSCarrierCount").Cells(1, Columns.Count).End(xlToLeft).Column
PRTSLastRow = Worksheets("PRTSCarrierCount").Cells(Rows.Count, 1).End(xlUp).Row
j = 1
Workbooks(W).Sheets("PRTSCarrierCount").Activate
For i = 1 To PRTSLastCol
Total = Cells(1, i).Value
If InStr(1, CStr(Total), "Total") > 0 Then
ColLtr = Replace(Cells(1, i).Address(True, False), "$1", "")
LastColLtr = Replace(Cells(1, PRTSLastCol + j).Address(True, False), "$1", "")
Range("ColLtr & 1: & ColLtr & PRTSLastRow").Select
'Columns("ColLtr & : & ColLtr").Select
Selection.Copy
Range("LastColLtr & 1").Select
ActiveSheet.Paste
j = j + 1
End If
Next i
Something like this?
Option Explicit
Sub Thing()
Dim PRTSLastRow As Long
Dim PRTSLastCol As Long
Dim ColLtr As String
Dim LastColLtr As String
Dim Total As String
Dim W As Workbook
Dim i As Long
Dim ws As Worksheet
Set W = ThisWorkbook 'Or ActiveWorkbook
Set ws = W.Worksheets("PRTSCarrierCount")
PRTSLastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
PRTSLastCol = GetLastCol(ws, 1)
With ws
For i = 1 To PRTSLastCol
Total = LCase$(.Cells(1, i).Text)
If InStr(1, Total, "total") > 0 Then
ColLtr = Replace(.Cells(1, i).Address(True, False), "$1", "")
.Range(ColLtr & "1:" & ColLtr & PRTSLastRow).Copy .Cells(1, GetLastCol(ws, 1) + 1)
i = i + 1
End If
Next i
End With
End Sub
Public Function GetLastCol(ByVal ws As Worksheet, rowNum As Long) As Long
With ws
GetLastCol = .Cells(rowNum, Columns.Count).End(xlToLeft).Column
End With
End Function
Or with Find
Public Sub Thing2()
Dim PRTSLastRow As Long
Dim PRTSLastCol As Long
Dim ColLtr As String
Dim LastColLtr As String
Dim Total As String
Dim W As Workbook
Dim ws As Worksheet
Dim searchRng As Range
Set W = ThisWorkbook 'Or ActiveWorkbook
Set ws = W.Worksheets("PRTSCarrierCount")
PRTSLastCol = GetLastCol(ws, 1)
Total = "total"
With ws
PRTSLastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set searchRng = .Range(.Cells(1, 1), .Cells(1, PRTSLastCol))
Dim gatheredRange As Range
Set gatheredRange = GatherRanges(Total, searchRng, PRTSLastRow)
If Not gatheredRange Is Nothing Then
gatheredRange.Copy .Cells(1, GetLastCol(ws, 1) + 1)
End If
End With
End Sub
Public Function GatherRanges(ByVal Total As String, ByVal searchRng As Range, ByVal PRTSLastRow As Long) As Range
Dim foundCell As Range
Set foundCell = searchRng.Find(Total)
If foundCell Is Nothing Then
MsgBox "Search term not found"
End
End If
Dim firstfoundCellAddress As String
firstfoundCellAddress = foundCell.Address
Dim gatheredRange As Range
Set gatheredRange = foundCell.Resize(PRTSLastRow, 1)
Do
Set foundCell = searchRng.FindNext(foundCell)
Set gatheredRange = Union(gatheredRange, foundCell.Resize(PRTSLastRow, 1))
Loop While firstfoundCellAddress <> foundCell.Address
Set GatherRanges = gatheredRange
End Function
Reference:
https://excelmacromastery.com/excel-vba-find/

Copy row above the row containing certain text

I have a code to copy the entire row if column B contains a certain text ("ACK-", but now I need to copy the entire row directly above the one with the certain text ("ACK-". Is this even possible? Any help will be appreciated.
Sub HEA_Filter()
Dim strArray As Variant
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim NoRows As Long
Dim DestNoRows As Long
Dim I As Long
Dim J As Integer
Dim rngCells As Range
Dim rngFind As Range
Dim Found As Boolean
strArray = Array("ack-")
Set wsSource = ActiveSheet
NoRows = wsSource.Range("A65536").End(xlUp).Row
DestNoRows = 1
Set wsDest = Sheets("Real Alarms")
For I = 1 To NoRows
Set rngCells = wsSource.Range("B" & I)
Found = False
For J = 0 To UBound(strArray)
Found = Found Or Not (rngCells.Find(strArray(J)) Is Nothing)
Next J
If Found Then
rngCells.EntireRow.Copy wsDest.Range("A" & DestNoRows)
DestNoRows = DestNoRows + 1
End If
Next I
End Sub
To reference "the row above", you can use the Range.Offset method:
rngCells.Offset(-1).EntireRow.Copy wsDest.Range("A" & DestNoRows)
' ^^^^^^^^^^^^
However, be aware that this raised a runtime error if the range is at row 1, because row 0 does not exist. You might want to add a check for it, for example:
If rngCells.Row > 1 Then rngCells.Offset(-1).EntireRow.Copy ...

VBA - ReDim Preserve creating false array element

This is a for loop to find values in a range and create new array full of match results. Problem is viewing the object I see at the first If statement AR2(i) creates an element AR2(0) which is empty then assigns AR2(1) as the If Else value.
Sub rt()
Dim AR0() As Variant, AR1() As Variant, AR2() As Variant
Dim WS0 As Worksheet, WS1 As Worksheet
Dim i As Integer, RW0 As Integer, RW1 As Integer
Dim C As Range
Set WS0 = Sheets("lookup")
Set WS1 = Sheets("centro")
RW1 = WS1.Cells(WS1.Rows.Count, "A").End(xlUp).row
AR0 = WS0.Range("A3:A28")
For i = 1 To UBound(AR0, 1)
With WS1.Range("A2:A" & RW1)
Set C = .find(AR0(i, 1), LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext)
ReDim Preserve AR2(i)
If Not C Is Nothing Then
AR2(i) = "YES"
Else
AR2(i) = " - "
End If
End With
Next
WS0.Range("B3:B28") = WorksheetFunction.Transpose(AR2)
End Sub
Error was with AR2 creating element AR2(0) without having value assigned. Solution was to set For loop to start from 0 and AR0(i +1, 1) to allow to find this value starting from loop position 0. Thanks!
Sub rt()
Dim AR0() As Variant, AR1() As Variant, AR2() As Variant
Dim WS0 As Worksheet, WS1 As Worksheet
Dim i As Integer, RW0 As Integer, RW1 As Integer
Dim C As Range
Set WS0 = Sheets("lookup")
Set WS1 = Sheets("centro")
RW1 = WS1.Cells(WS1.Rows.Count, "A").End(xlUp).row
AR0 = WS0.Range("A3:A28")
For i = 0 To UBound(AR0, 1) - 1
With WS1.Range("A2:A" & RW1)
Set C = .find(AR0(i + 1, 1), LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext)
ReDim Preserve AR2(i)
If Not C Is Nothing Then
AR2(i) = "YES"
Else
AR2(i) = " - "
End If
End With
Next
WS0.Range("B3:B28") = WorksheetFunction.Transpose(AR2)
End Sub

Resources