Search code examples
excelvbaloopsfor-loopcopy-paste

Expand existing Copy-Paste Loop: Loop through specific Columns based on Cell Value


I currently have multiple excel spreadhsheets that look like this:

My Table

The table is a questionnaire with answers from column C-F, C is the "worst" (letter N), D the "second worst" (letter T), E the second best (letter W) and F the best (letter G as in Good).

To the right of this table are sentences that I copy to another Spreadsheet using an existing module, depending on where the "x" in the questionnaire is set (it always copies the sentence 9 rows to the right of the "x").

Now I want to modify my existing code to not just copy all the sentences from every row, but only copy 5 for each Worksheet. These 5 should be either the 5 "best" answers (5 from column F, meaning Good as answer in questionnaire, if there are less than 5 in that column then take the rest from column E until you have 5) or the 6 "worst" answers, meaning 5 from column C(letter N as in not good) and if there are less than 5 "X" in that column take the rest from column D (letter T). This way I want to copy the 5 best or worst answers for each Worksheet. The decision if the best or worst answers should be copied depends on one simple Cell Value (Cell K6) in each Worksheet. If K6 >70% take the best answers, if K6 is under 70%, take the worst answers.

This is my current module to copy all the answers to my new worksheet:

Dim ws As Worksheet
Dim lr As Integer 'lastrow
Dim SpaltenIndex As Integer
Dim SheetNummer As Integer
Dim cl As Range 'cell
Dim rw As Range 'row
Dim Antwortrange As String
Dim WrkSht As Worksheet
Dim WrkShtCol As Sheets


'Create Destination Sheet
Sheets.Add
ActiveSheet.Name = "Handlungsempfehlungen"

'Set Questionnaire Answer Range to search through
Antwortrange = "C11:F400"

'ColumnIndex and SheetNumber
SpaltenIndex = 1
SheetNummer = 1

'Create Worksheet Collection with all the Questionnaire-Sheets
Set WrkShtCol = Worksheets(Array("AM AD - Anforderungsdefinition", "AM AA - Anforderunganalyse", "AM - Anforderungsdokumentation", "AM AV - Anforderungsvalidierung", "TM IT - Initiierung Test", "TM ZD - Zieldefinition", "TM TV - Testvorgehen", "TM TOB - Testobjektabgrenzung", "TM AS - Aufwandsschätzung", "TM TP - Testplanung", "TM TP - Testplanung", "TM TA - Testauftrag", "TM TS - Teststeuerung", "TM AO - Aufbauorganisation", "TM RM - Risikomanagement", "TM MI - Managementinformation", "TM AF - Abnahme Freigabe", "TM AT - Abschluss Test", "DT IT - Installationstest", "DT ST - Sicherheitstest", "OTP DT - Dokumententest", "OTP MT - Modultest", "OTP MIT - Modulintegrationstest", "OTP OO KT - OO Klassentest", "OTP OO KIT - OO Klassenintgrate", "OTP FT - Funktionstest", "OTP FIT - Funktionsintgratiotes", "OTP PIT - Produktintegratest", "OTP AT - Abnahmetest", "OTP ET - Ergonomietest", "OTP LPT - Last & Performance", "OTP GPT - Geschäftsprozesstest", "TUP TMK -Testumg Module Klassen", _
"TUP TUF - Testumgebung Funktion", "TUP TP - Testumgebung Prozesse", "ATP KM Konfigurationsmanagement", "ATP FAEM - Fehler Änderungs", "ATP DS - Datensicherheit", "ATP DSCH - Datenschutz", "ATP TEV -Testergebnisverwaltung", "ATP VG - Vertragsgestaltung"))
   
'MAIN LOOP: Take all sentences 9 rows to the right of each X in each Questionnaire and paste the value to the newly created sheet from above

For Each WrkSht In WrkShtCol

   For Each rw In WrkSht.Range(Antwortrange).Rows   
   For Each cl In rw.Cells
       
   lr = ws.Cells(ws.Rows.Count, SpaltenIndex).End(xlUp).Offset(1).Row
   If lr = 2 And ws.Range("A1") = "" And lr < 500 Then lr = 1
   'If lr = 2 And ws.Range("A2") = "" Then lr = 1
      
           If LCase(cl.Value) = "x" Then
               cl.Offset(0, 9).Copy Sheets("Handlungsempfehlungen").Cells(lr, SpaltenIndex)       
           End If
       Next cl
   Next rw



'If 1st row is empty in destination sheet, delete and shift rest up 
If Sheets("Handlungsempfehlungen").Cells(1, SpaltenIndex) = "" Then Sheets("Handlungsempfehlungen").Cells(1, SpaltenIndex).Delete Shift:=xlUp

'WrkShtCol(1).range("A2").Copy Worksheets("Handlungsempfehlungen").Cell(lr, SpaltenIndex)

Sheets("Handlungsempfehlungen").Cells(35, SpaltenIndex).Value = WrkShtCol(SheetNummer).Cells(2, 1)


SpaltenIndex = SpaltenIndex + 1
SheetNummer = SheetNummer + 1


End Sub

I hope you can help me, any tips would be greatly appreciated. Thank you so much in advance.

Edit - Expected Results:

If K6 is over 70% - find the 5 best answers (1st priority column F, if there are 5 "x" in column F, find those Cells and copy the value 9 rows to the right to the new sheet.

So if the questionnaire looks like this: QuestionnaireOver70% The pasted table should look like this: Table

And if the questionnaire is under 70%, do the same but for the worst (Column C & D, C being the worst, if there are not 5 "x" in C then take the rest from D (second worst))

Hope this helps

EDIT: the File with all the sheets I want to copy from and the current module: https://www.dropbox.com/sh/wq8dgzmlpxgm76x/AACOG_SkE9WMqE22qvcd3tVBa?dl=0

EDIT: Updated link, excel file has more explanation with needed steps and worksheets to help understand (One with current output, one with desired output)


Solution

  • Read code's comments and adjust it to fit your needs

    Option Explicit
    
    Public Sub DoSomething()
    
        ' Define the results sheet's name
        Dim resultsSheetName As String
        resultsSheetName = "Handlungsempfehlungen"
        
        ' Set the results sheet reference
        Dim resultsSheet As Worksheet
        Set resultsSheet = ThisWorkbook.Worksheets(resultsSheetName)
    
        ' Define the sheets to evaluate in an array
        Dim targetSheets As Sheets
        Set targetSheets = ThisWorkbook.Worksheets(Array("AM AD - Anforderungsdefinition", "AM AA - Anforderunganalyse", _
                            "AM - Anforderungsdokumentation", "AM AV - Anforderungsvalidierung", _
                            "TM IT - Initiierung Test", "TM ZD - Zieldefinition", _
                            "TM TV - Testvorgehen", "TM TOB - Testobjektabgrenzung", _
                            "TM AS - Aufwandsschätzung", "TM TP - Testplanung", _
                            "TM TP - Testplanung", "TM TA - Testauftrag", _
                            "TM TS - Teststeuerung", "TM AO - Aufbauorganisation", _
                            "TM RM - Risikomanagement", "TM MI - Managementinformation", _
                            "TM AF - Abnahme Freigabe", "TM AT - Abschluss Test", _
                            "DT IT - Installationstest", "DT ST - Sicherheitstest", _
                            "OTP DT - Dokumententest", "OTP MT - Modultest", _
                            "OTP MIT - Modulintegrationstest", "OTP OO KT - OO Klassentest", _
                            "OTP OO KIT - OO Klassenintgrate", "OTP FT - Funktionstest", _
                            "OTP FIT - Funktionsintgratiotes", "OTP PIT - Produktintegratest", _
                            "OTP AT - Abnahmetest", "OTP ET - Ergonomietest", _
                            "OTP LPT - Last & Performance", "OTP GPT - Geschäftsprozesstest", _
                            "TUP TMK -Testumg Module Klassen", "TUP TUF - Testumgebung Funktion", _
                            "TUP TP - Testumgebung Prozesse", "ATP KM Konfigurationsmanagement", _
                            "ATP FAEM - Fehler Änderungs", "ATP DS - Datensicherheit", _
                            "ATP DSCH - Datenschutz", "ATP TEV -Testergebnisverwaltung", _
                            "ATP VG - Vertragsgestaltung"))
    
        ' Loop through each sheet
        Dim targetSheet As Worksheet
        For Each targetSheet In targetSheets
            
            ' Get last row in target sheet
            Dim lastRow As Long
            lastRow = targetSheet.Cells(targetSheet.Rows.Count, "A").End(xlUp).Row
            
            'targetSheet.Activate
            
            ' Remove any filters
            If targetSheet.FilterMode Then targetSheet.ShowAllData
            
            ' Set the range with X
            Dim rangeToFilter As Range
            Set rangeToFilter = targetSheet.Range("C7:F" & lastRow)
        
            ' Define a counter to check how many X there are
            Dim resultCounter As Long
            resultCounter = 1
            
            ' Check the grade (
            Dim gradeValue As Variant
            gradeValue = targetSheet.Range("K6").Value
            
            ' Check if the grade is not an error
            If Not IsError(gradeValue) Then
                
                ' Define the columns to filter (in order) according to the grade value
                Select Case gradeValue
                Case Is > 0.7
                        
                    Dim columnsToFilter As Variant
                    columnsToFilter = Array(4, 3) ' Columns F and E
                    
                Case Else
                    
                    columnsToFilter = Array(1, 2) ' Columns C and D
                    
                End Select
                
                ' Set a reference to the range that holds the Xs in first column
                Dim resultRange As Range
                Set resultRange = filterRange(rangeToFilter, columnsToFilter(0), "X")
                
                ' If there are any results in first column
                If Not resultRange Is Nothing Then
                    ' Count them
                    Dim countResult As Long
                    countResult = resultRange.Count
                    
                    ' Get the results sheet's last row
                    Dim resultsRow As Long
                    resultsRow = resultsSheet.Cells(resultsSheet.Rows.Count, "A").End(xlUp).Row
                    
                    ' Print the results in results sheet
                    printResults resultsSheet, resultsRow, resultRange, resultCounter
                    
                End If
    
                ' If the results with Xs are less than five
                If resultCounter <= 5 Then
                    ' Remove filters from sheet
                    If targetSheet.FilterMode Then targetSheet.ShowAllData
                    
                    ' Set a reference to the range that holds the Xs in second column
                    Set resultRange = filterRange(rangeToFilter, columnsToFilter(1), "X")
                    
                    ' If there are any results in second column
                    If Not resultRange Is Nothing Then
                        
                        ' Print the results in results sheet
                        printResults resultsSheet, resultsRow, resultRange, resultCounter
                    End If
                End If
                
            End If
            
        Next targetSheet
    
    End Sub
    
    Private Function filterRange(ByVal rangeToFilter As Range, ByVal fieldToFilter As Long, ByVal criteriaToFilter As String) As Range
        
        ' Apply auto filter in selected column
        rangeToFilter.AutoFilter Field:=fieldToFilter, Criteria1:=criteriaToFilter
        
        ' Use error handling to handle the case in which there aren't any results
        On Error Resume Next
        Set filterRange = rangeToFilter.Offset(1, 0).Columns(fieldToFilter).SpecialCells(xlCellTypeVisible)
        On Error GoTo 0
    End Function
    
    ' In this sub is used the variable resultCounter ByRef which means that the value is passed back to the variable that is in the calling procedure
    Private Sub printResults(ByVal resultsSheet As Worksheet, ByVal resultsRow As Long, ByVal resultRange As Range, ByRef resultCounter As Long)
        
        Dim targetCell As Range
        For Each targetCell In resultRange
            
            If resultCounter <= 5 Then
                resultsSheet.Range("A" & resultsRow + resultCounter).Resize(1, 3).Value = Array(resultRange.Parent.Name, resultCounter, targetCell.Offset(0, 9).Value)
            Else
                Exit For
            End If
            
            resultCounter = resultCounter + 1
            
        Next targetCell
        
    End Sub
    

    PS. I could't understand the output in "Handlungsempfehlungen" so I left a generic one

    Let me know if it works