Translating Conditional Formatting to VBA codes - vba

I have to apply two conditional formatting to my data in a sheet called "Report" (num of rows are not fixed). I can do these via the "Manage Rules" option via conditional formatting. So I tried to record macro but unfortunately I don't see any codes recorded.
Conditional Formatting 1:
=$F5="NH Orientation" , then Color (242,220,219)
Conditional Formatting 2:
=OR($O4<4,$G4="Elective"), then color (242,220,219)
Post which I will cut and paste the colored cells in row 2 and below in another sheet called "Removed"
I want to have these conditions in macro in my excel.

You decide how to tweak but the following are the main elements:
Option Explicit
Public Sub AddRules()
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ThisWorkbook
Set ws = ThisWorkbook.Worksheets("Report") ' change
Dim rule1 As FormatCondition
Dim rule2 As FormatCondition
Dim lastRow As Long
lastRow = GetLastRow(ws, 1)
If lastRow < 4 Then
MsgBox "Invalid number of rows"
Exit Sub
End If
With ws.Range("A4:V" & lastRow)
.FormatConditions.Delete
Set rule1 = .FormatConditions.Add(Type:=xlExpression, _
Formula1:="=$F5=""NH Orientation""")
rule1.StopIfTrue = True 'Change as required
Set rule2 = .FormatConditions.Add(Type:=xlExpression, _
Formula1:="=OR($O4<4,$G4=""Elective"")")
Dim i As Long
For i = 1 To 2
With .FormatConditions(i)
With .Interior
.PatternColorIndex = xlAutomatic
.Color = RGB(242, 220, 219)
.TintAndShade = 0
End With
End With
Next i
End With
End Sub
Public Function GetLastRow(ByVal ws As Worksheet, Optional ByVal columnNumber As Long = 1) As Long
With ws
GetLastRow = .Cells(.Rows.Count, columnNumber).End(xlUp).Row
End With
End Function
Reference:
https://msdn.microsoft.com/en-us/vba/excel-vba/articles/formatconditions-add-method-excel

I modified as below and it is working now. Please advise if this can be improved.
Sub AddRules()
Dim ws As Worksheet
Set ws = Sheets("Report")
Dim lastRow As Long
lastRow = GetLastRow(ws, 1)
If lastRow < 4 Then
MsgBox "Invalid number of rows"
Exit Sub
End If
With ws.Range("A4:V" & lastRow)
.FormatConditions.Delete
Set rule1 = .FormatConditions.Add(Type:=xlExpression, _
Formula1:="=$F4=""NH Orientation""")
With rule1
.Interior.Color = RGB(242, 250, 219)
End With
End With
With ws.Range("A4:V" & lastRow)
Set rule2 = .FormatConditions.Add(Type:=xlExpression,Formula1:="=AND($O4<4,$G4=""Elective"")")
With rule2
.Interior.Color = RGB(242, 210, 219)
End With
End With
End Sub
Function GetLastRow(ByVal ws As Worksheet, Optional ByVal columnNumber As Long = 1) As Long
With ws
GetLastRow = .Cells(.Rows.Count, columnNumber).End(xlUp).Row
End With
End Function

Related

Cut and Paste into a sheet with Case-Select

I am new to writing macros and trying to write one for work. Below is a piece of code I have been fighting with. I want it to look at sheet "NG304" and find key words listed in column B. If the key words are there, move them to the second spreadsheet "Payroll Detail". Issues i'm having - the code is not going through the whole list and it doesn't seem to be pasting in the next available row on the payroll detail spreadsheet (it will simply paste on top of my header).
Code:
Dim Findme As String, Findwhat As String, c As Range
With ActiveWorkbook.Worksheets("NG304")
For Each c In .Range(.Cells(2, "B"), .Cells(Rows.Count, "B").End(xlUp))
Findwhat = vbNullString
Findme = StrConv(c.Value2, vbProperCase)
Select Case True
Case Findme Like "VCIP"
Findwhat = "VCIP"
Case Findme Like "Company Labor"
Findwhat = UCase(Findme)
Case Else
'do nothing
End Select
If CBool(Len(Findwhat)) Then
With .Parent.Worksheets("NG304")
c.EntireRow.Cut Destination:=Worksheets("Payroll Detail").Range("A" & lastrow + 1)
lastrow = lastrow + 1
End With
End If
Next c
End With
This will filter each value defined in K_WORDS (at the top), and move the rows to the other sheet:
Option Explicit
Public Sub moveKeywordRows()
Const K_WORDS As String = "VCIP,Company Labor" '<------- Defined keywords
Dim wsFrom As Worksheet, wsDest As Worksheet, kw As Variant, i As Long, lr As Long
Set wsFrom = ThisWorkbook.Worksheets("NG304")
Set wsDest = ThisWorkbook.Worksheets("Payroll Detail")
kw = Split(K_WORDS, ",")
Application.ScreenUpdating = False
For i = 0 To UBound(kw)
lr = wsDest.Cells(wsDest.Rows.Count, "B").End(xlUp).Row
With wsFrom.UsedRange
.AutoFilter Field:=2, Criteria1:="=" & kw(i)
.Copy
wsDest.Cells(lr, "A").PasteSpecial xlPasteAll
.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
Application.CutCopyMode = False
wsDest.Activate: wsDest.Cells(1, "A").Select
Next
wsDest.UsedRange.EntireColumn.AutoFit
With wsFrom
.Activate 'wsFrom.UsedRange.AutoFilter '.ShowAllData
End With
Application.ScreenUpdating = True
End Sub
This is your posted code, with some adjustments - it seems to be working:
Public Sub moveKeywordRows1()
Dim FindMe As String, FindWhat As String, c As Range, lr As Long, wsDest As Worksheet
Set wsDest = ThisWorkbook.Worksheets("Payroll Detail")
With ThisWorkbook.Worksheets("NG304")
Application.ScreenUpdating = False
For Each c In .Range(.Cells(2, "B"), .Cells(.Rows.Count, "B").End(xlUp))
FindMe = StrConv(c.Value2, vbProperCase)
FindWhat = vbNullString
Select Case UCase(FindMe)
Case "VCIP": FindWhat = "VCIP"
Case UCase("Company Labor"): FindWhat = "Company Labor"
End Select
If Len(FindWhat) > 0 Then
c.EntireRow.Cut Destination:=wsDest.Range("A" & lr + 1)
lr = lr + 1
End If
Next
Application.ScreenUpdating = True
End With
End Sub

Excel VBA printout and define dynamic print area

i'm actually trying to, for a command button, set a print area based on colomn A (if A is empty then this row is last row. and when the print area is set, just print it out with landscape layout. My code for now is as follow. When i clic it prints but doesn't update the print area can you help me plz
Private Sub Imprimer_Click()
ActiveSheet.Unprotect Password:="mypass"
Dim usedRangeEx As Range
Set usedRangeEx = GetUsedRangeIncludingCharts(ActiveSheet)
usedRangeEx.Activate
Debug.Print usedRangeEx.Address
ActiveSheet.Protect Password:="mypass"
End Sub
Private Function GetUsedRangeIncludingCharts(target As Worksheet) As Range
ActiveSheet.Unprotect Password:="mypass"
Dim firstRow As Long
Dim firstColumn As Integer
Dim lastRow As Long
Dim lastColumn As Integer
Dim oneChart As ChartObject
For Each cell In Range("A5:A65")
If Not IsEmpty(cell) Then
lastRow = cell.Row
End If
Next
With target
firstRow = .UsedRange.cells(1).Row
firstColumn = .UsedRange.cells(1).Column
lastColumn = .UsedRange(.UsedRange.cells.Count).Column
Set GetUsedRangeIncludingCharts = .Range(.cells(firstRow, firstColumn), _
.cells(lastRow, lastColumn))
End With
ThisWorkbook.ActiveSheet.PrintOut
With ActiveSheet.PageSetup
.Zoom = False
.FitToPagesTall = 1
.FitToPagesWide = 1
End With
ActiveSheet.Protect Password:="mypass"
End Function
Set your print area
Sub Button1_Click()
Dim LstRw As Long, PrnG As Range
LstRw = Cells(Rows.Count, "A").End(xlUp).Row
Set PrnG = Range("A1:C" & LstRw) ' or whatever column you want
ActiveSheet.PageSetup.PrintArea = PrnG.Address
End Sub

Dynamic Sheet naming and copying data

I have been a silent reader on here for a few months but have been struggling with this code for a week now, so thought i would see if anyone can help.
I have a worksheet where sheet 1 contains information for users to input data.
Column A ask a question, column C is where the user will type in an answer.
Row 4 asks how many configurations there will be. depending on what number they input depends on how many cells light up to the right ie if 1 then D4 goes yellow, if 2 then D4 and E4 go yellow (using conditional formatting)
The user will then enter the title into the highlighted cell (D4,E4 ,F4 etc)
I want to create a new sheet at the end of the sheet for each configuration.
then NAME the new sheet by the text entered in D4, E4 etc.
the code I have so far is:
Option Explicit
Sub InsertSupplierSheet()
Dim ws As Worksheet
Dim tmpSht As Worksheet
Dim Lastcol As Integer, i As Integer, j As Integer
Dim DESCRANGE As Range
'~~> Change Sheet1 to the sheet which has all the data
Set ws = ThisWorkbook.Worksheets(1)
With ws
Lastcol = ActiveSheet.Cells(4, Columns.Count).End(xlToLeft).Column
If Lastcol < 4 Then Exit Sub
For i = 3 To Lastcol
If DoesSheetExist(ActiveSheet.Cells(4 & i).Value) Then
Set tmpSht = ActiveSheet.Cells(4 & i).Value
Else
Sheets.Add After:=Sheets(Sheets.Count)
Set tmpSht = ActiveSheet
tmpSht.Name = "NEWSHEET"
End If
.Rows("1:3").Copy tmpSht.Rows(1)
For j = 1 To 4
tmpSht.Columns(j).ColumnWidth = .Columns(j).ColumnWidth
Next j
.Rows(i).Copy tmpSht.Rows(4)
Next
End With
End Sub
Function DoesSheetExist(Sht As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(ws)
On Error GoTo 0
If Not ws Is Nothing Then DoesSheetExist = True
End Function
I put in "NEWSHEET" to see if even creates a new sheet, but it still fails. I just cant see where I am going wrong.
Any help /advise is welcomed.
EDIT .
I cant work out why though.
The last col will be H4 so lastcol would be "8" .
Then for i = 4 to 8 run the loop. there are descriptions in each of the cells in row 4 so i don't see why it would work for 2 instantness and then fail ?
I dont know if this would make it easier but I have the number of sheets i want to create in cell C4 so i could use this rather than looking up populated cells. so if C4 is 2 then I want to add 2 sheets named as the content of D4, E4. if C4 is 3 then I want to add 3 sheets names as content of D3,E3,F3. Am I making this harder than I need too ?
UPDATE
I figured out the copying over of info is affecting this loop. and amended the code to this.
Sub InsertSupplierSheet()
Dim ws As Worksheet
Dim tmpSht As Worksheet
Dim Lastcol As Integer, i As Integer, j As Integer
Dim DESCRANGE As Range
Dim sShtName As String 'Dimension sheet name variable
'~~> Change Sheet1 to the sheet which has all the data
Set ws = ThisWorkbook.Worksheets(1)
With ws
Lastcol = ActiveSheet.Cells(4, Columns.Count).End(xlToLeft).Column
If Lastcol < 4 Then Exit Sub
For i = 4 To Lastcol
sShtName = ActiveSheet.Cells(4, i).Value2 'Set sShtName to cell value within loop
If DoesSheetExist(sShtName) Then 'Use sShtName to call "Exists" function
Set tmpSht = Sheets(sShtName)
Else
Sheets.Add After:=Sheets(Sheets.Count)
Set tmpSht = ActiveSheet
tmpSht.Name = sShtName 'Change name to sShtName
End If
.Rows("1:3").Copy tmpSht.Rows(1)
.Rows(13).Copy tmpSht.Rows(4)
Next
End With
End Sub
Function DoesSheetExist(Sht As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(Sht)
On Error GoTo 0
If Not ws Is Nothing Then DoesSheetExist = True
End Function
this is doing what i want it to do with a couple of small exceptions.
the Sheets are being named by the cells in D1 , then E13,F13,G13,H13 So i need to figure out where that info is coming from.
the final bit is that due to my conditional formatting in the First sheet, I am getting text on black backgrounds in the copy cells, but that is the very least of my worries !
UPDATE
Found the error -
sShtName = ActiveSheet.Cells(4, i).Value2
should be
sShtName = Worksheets(1).Cells(4, i).Value2
You are calling your cells incorrectly. Use (4, i) instead of (4 & i).
The way you were calling it concatenated it to 43, which resulted in you checking cell AQ1 (AQ being the 43rd column) for the sheet reference.
Edit: I just walked through it a bit and found a couple of other errors. You need to set the sheet name to sht in your 'exists' function, and I'm assuming you want to set tmpSht to a sheet, so you need to encase it in sheets(). Try this:
Sub InsertSupplierSheet()
Dim ws As Worksheet
Dim tmpSht As Worksheet
Dim Lastcol As Integer, i As Integer, j As Integer
Dim DESCRANGE As Range
Dim sShtName As String 'Dimension sheet name variable
'~~> Change Sheet1 to the sheet which has all the data
Set ws = ThisWorkbook.Worksheets(1)
With ws
Lastcol = ActiveSheet.Cells(4, Columns.Count).End(xlToLeft).Column
If Lastcol < 4 Then Exit Sub
For i = 4 To Lastcol
sShtName = ActiveSheet.Cells(4, i).Value2 'Set sShtName to cell value within loop
If DoesSheetExist(sShtName) Then 'Use sShtName to call "Exists" function
Set tmpSht = Sheets(sShtName)
Else
Sheets.Add After:=Sheets(Sheets.Count)
Set tmpSht = ActiveSheet
tmpSht.Name = sShtName 'Change name to sShtName
End If
.Rows("1:3").Copy tmpSht.Rows(1)
For j = 1 To 4
tmpSht.Columns(j).ColumnWidth = .Columns(j).ColumnWidth
Next j
.Rows(i).Copy tmpSht.Rows(4)
Next
End With
End Sub
Function DoesSheetExist(Sht As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(Sht)
On Error GoTo 0
If Not ws Is Nothing Then DoesSheetExist = True
End Function
Instead of adding the new sheet and then setting the activesheet to the tmpsht you could use a shorter way (see below). And why did you set the ws if you don't use it....
Sub InsertSupplierSheet()
Dim ws As Worksheet
Dim tmpSht As Worksheet
Dim Lastcol As Integer, i As Integer, j As Integer
Dim DESCRANGE As Range
Set ws = ThisWorkbook.Worksheets(1)
With ws
Lastcol = .Cells(4, .Columns.Count).End(xlToLeft).Column
If (Lastcol < 4) Then
Exit Sub
End If
For i = 4 To Lastcol
If (DoesSheetExist(.Cells(4, i).Value2) = True) Then
Set tmpSht = Sheets(.Cells(4, i).Value)
Else
Set tmpSht = Sheets.Add After:=Sheets(Sheets.Count)
tmpSht.Name = "NEWSHEET"
End If
.Rows("1:3").Copy tmpSht.Rows(1)
For j = 1 To 4
tmpSht.Columns(j).ColumnWidth = .Columns(j).ColumnWidth
Next j
.Rows(i).Copy tmpSht.Rows(4)
Next i
End With
End Sub
Function DoesSheetExist(Sht As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(Sht)
On Error GoTo 0
If Not ws Is Nothing Then
DoesSheetExist = True
Else
DoesSheetExist = False
End If
End Function
This was my final code. There were a few tweaks, Firstly I added a formula in row 6 to shorten the name of row 4 to a 10 character name as I found the tab names were too long (hence the code for the naming refers to row 6. I also added some custom text to add into each sheet and some formatting
Option Explicit
Sub InsertSupplierSheet()
Dim ws As Worksheet
Dim tmpSht As Worksheet
Dim Lastcol As Integer
Dim i As Integer
Dim j As Integer
Dim DESCRANGE As Range
Dim sShtName As String 'Dimension sheet name variable
'~~> Change Sheet1 to the sheet which has all the data
Set ws = ThisWorkbook.Worksheets(1)
With ws
Lastcol = ActiveSheet.Cells(4, Columns.Count).End(xlToLeft).Column ' work with the template sheet
If Lastcol = 3 Then Exit Sub 'repeat these steps from the first config to the last
For i = 4 To Lastcol
sShtName = Worksheets(1).Cells(6, i).Value2 'Set sShtName to cell value within loop
If DoesSheetExist(sShtName) Then 'Use sShtName to call "Exists" function
Set tmpSht = Sheets(sShtName)
Else
Sheets.Add After:=Sheets(Sheets.Count)
Set tmpSht = ActiveSheet
tmpSht.Name = sShtName 'Change name to sShtName tmpSht.Name = sShtName
End If
.Rows("1:3").Copy tmpSht.Rows(1) ' Format the cell width in the new sheet
.Rows(13).Copy tmpSht.Rows(4)
tmpSht.Range("A1").Value = Worksheets(1).Cells(4, i).Value2
Range("A1").ColumnWidth = 30
Range("B1").ColumnWidth = 0
Range("C1").ColumnWidth = 30
Range("D1:K1").ColumnWidth = 10
Range("D4:J4").Font.Color = vbWhite ' format the colour of the text in the new sheet
Range("C1") = " " ' Negate info in cell C1
With Range("A1:M5") ' add borders
'Clear existing
.Borders.LineStyle = xlNone
'Apply new borders
.BorderAround xlContinuous
.Borders(xlInsideHorizontal).LineStyle = xlContinuous
.Borders(xlInsideVertical).LineStyle = xlContinuous
End With
With Range("A1:C4") ' set colours for the new sheet
.Font.Color = vbBlack
.Interior.Color = vbWhite
End With
Range("D4:J4").Font.Color = vbWhite ' set colour of the numbers to white to show on black background
Range("A5") = "Unit cost in " & Worksheets(1).Cells(17, 3).Value2
Range("A6") = "CUSTOM TEXT ONE."
Range("A7") = "NOTE if quantity " & Range("D4").Value2 + 5 & " is ordered then total cost will be your unit cost for " & Range("D4").Value2 & " multiplied by " & Range("D4").Value2 + 5 & " .This applies up to the quantity of " & Range("E4").Value2 - 1
Range("A8") = "CUSTOM TEXT 2"
Next i
End With
End Sub
Function DoesSheetExist(Sht As String) As Boolean
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(Sht)
On Error GoTo 0
If Not ws Is Nothing Then DoesSheetExist = True
End Function

Separate Excel rows into individual sheets and retain header

I am trying to use VBA in Excel to separate rows into separate sheets and retain headers. Below is what I have so far. It works except I get the header row, then the individual row I want to move to the sheet is there BUT it's there three times instead of one. I am basically going by trial and error and I am stumped. Help please! I have no experience with this:
Sub DispatchTimeSeriesToSheets()
Dim ws As Worksheet
Set ws = Sheets("Scoring")
Dim LastRow As Long
LastRow = Range("A" & ws.Rows.Count).End(xlUp).Row
' stop processing if we don't have any data
If LastRow < 2 Then Exit Sub
Application.ScreenUpdating = False
SortScoring LastRow, ws
CopyDataToSheets LastRow, ws
ws.Select
Application.ScreenUpdating = True
End Sub
Sub SortScoring(LastRow As Long, ws As Worksheet)
ws.Range("A4:W" & LastRow).Sort Key1:=ws.Range("A4"), Key2:=ws.Range("W4")
End Sub
Sub CopyDataToSheets(LastRow As Long, src As Worksheet)
Dim rng As Range
Dim cell As Range
Dim Series As String
Dim SeriesStart As Long
Dim SeriesLast As Long
Set rng = Range("A4:A" & LastRow)
SeriesStart = 2
Series = Range("A" & SeriesStart).Value
For Each cell In rng
If cell.Value <> Series Then
SeriesLast = cell.Row - 1
CopySeriesToNewSheet src, SeriesStart, SeriesLast, Series
Series = cell.Value
SeriesStart = cell.Row
End If
Next
' copy the last series
SeriesLast = LastRow
CopySeriesToNewSheet src, SeriesStart, SeriesLast, Series
End Sub
Sub CopySeriesToNewSheet(src As Worksheet, Start As Long, Last As Long, _
name As String)
Dim tgt As Worksheet
If (SheetExists(name)) Then
MsgBox "Sheet " & name & " already exists. " _
& "Please delete or move existing sheets before" _
& " copying data from the Scoring.", vbCritical, _
"Time Series Parser"
End
End If
Worksheets.Add(After:=Worksheets(Worksheets.Count)).name = name
Set tgt = Sheets(name)
' copy header row from src to tgt
tgt.Range("A1:W1").Value = src.Range("A1:W1").Value
' copy data from src to tgt
tgt.Range("A4:W" & Last - Start + 2).Value = _
src.Range("A" & Start & ":W" & Last).Value
End Sub
Function SheetExists(name As String) As Boolean
Dim ws As Worksheet
SheetExists = True
On Error Resume Next
Set ws = Sheets(name)
If ws Is Nothing Then
SheetExists = False
End If
End Function
Try this:
Sub doitall()
Dim ows As Worksheet
Dim tws As Worksheet
Dim rng As Range
Dim cel As Range
Dim LastRow As Long
Dim tLastRow As Long
Set ows = Sheets("Scoring")
With ows
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng = .Range("A4:A" & LastRow)
For Each cel In rng
If Not SheetExists(cel.Value) Then
Set tws = Worksheets.Add(After:=Sheets(Worksheets.Count))
tws.Name = cel.Value
tws.Rows(1).Resize(3).Value = .Rows(1).Resize(3).Value
Else
Set tws = Sheets(cel.Value)
End If
tLastRow = tws.Range("A" & tws.Rows.Count).End(xlUp).Offset(1).Row
tws.Rows(tLastRow).Value = .Rows(cel.Row).Value
Next
End With
End Sub
Function SheetExists(SName As String, _
Optional ByVal WB As Workbook) As Boolean
On Error Resume Next
If WB Is Nothing Then Set WB = ActiveWorkbook
SheetExists = CBool(Len(WB.Sheets(SName).Name))
End Function
This will do what you are looking for
Const HeaderRow = 3
Sub MoveRecordsByValues()
Dim ws As Worksheet
Dim dws As Worksheet
Dim SheetName As String
Application.DisplayAlerts = False
For Each ws In Sheets
If ws.name <> "Scoring" Then ws.Delete
Next ws
Set ws = Sheets("Scoring")
StartRow = HeaderRow + 1
LastRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
For RowCounter = StartRow To LastRow
SheetName = ws.Cells(RowCounter, 1)
If Not SheetExists(SheetName) Then SetUpSheet SheetName, ws, HeaderRow
Set dws = Worksheets(SheetName)
DestLastRow = dws.Range("A" & dws.Rows.Count).End(xlUp).Row + 1
ws.Rows(RowCounter).Copy dws.Cells(DestLastRow, 1)
Next RowCounter
Application.DisplayAlerts = True
End Sub
Function SheetExists(name As String) As Boolean
SheetExists = True
On Error GoTo errorhandler
Sheets(name).Activate
Exit Function
errorhandler:
SheetExists = False
End Function
Sub SetUpSheet(name, SourceSheet, HeaderRow)
Dim DestSheet As Worksheet
Set DestSheet = Sheets.Add
DestSheet.name = name
SourceSheet.Rows(1).Copy DestSheet.Cells(1, 1)
SourceSheet.Rows(2).Copy DestSheet.Cells(2, 1)
SourceSheet.Rows(3).Copy DestSheet.Cells(3, 1)
End Sub

VBA, Advanced Filter Based on Header

I have an advanced filter macro to run in excel that filters certain columns for unique data. I have a bunch of workbooks as well, and have certain headers that are identical across these workbooks, but headers in each workbook may differ in columns.
So header 'Stackoverflow' may be Column F in one file, and Column E in another. I just want to alter my code to something generic so it gets filter this column with a particular header no matter which workbook (Instead of filtering e:e, f:f, etc). any input is appreciated.
EDIT: this is my full macro, the part where I filter is a bit further down.
Here is my code:
Sub stkoverflow()
Dim ws As Worksheet
Dim wks As Excel.Worksheet
Dim wksSummary As Excel.Worksheet
Dim y As Range
Dim intRow As Long, i As Integer
Dim r As Range, lr As Long, myrg As Range
For Each ws In ActiveWorkbook.Worksheets
ws.Activate
lr = Cells(Rows.Count, "c").End(3).Row
Set myrg = Range("f2:f" & lr)
myrg.ClearContents
myrg.Formula = "=IFERROR(LEFT(e2,FIND(""_"",e2,1)-1),LEFT(e2,2))"
myrg.Value = myrg.Value
Range("f1").Value = "Test"
Next ws
On Error Resume Next
Set wksSummary = Excel.ActiveWorkbook.Worksheets("Unique data")
On Error GoTo 0
If wksSummary Is Nothing Then
Set wksSummary = Excel.ActiveWorkbook.Worksheets.Add
wksSummary.Name = "Unique data"
End If
For Each wks In Excel.ActiveWorkbook.Worksheets
With wksSummary
If wks.Name <> .Name Then
' THIS SECTION OF CODE IS POINTLESS. 'r' WILL ALWAYS BE DECLARED IRRESPECTIVE OF THE 'IF' STATEMENT
' If Application.WorksheetFunction.CountA(wks.Range("f:f")) Then
' Dim r As Range
' End If
With wksSummary
If wks.Name <> .Name Then
If Application.WorksheetFunction.CountA(wks.Range("a:a")) Then
Set r = .Cells(.Cells(.Rows.Count, 4).End(xlUp).Row + 1, 4)
Set y = .Cells(.Cells(.Rows.Count, 5).End(xlUp).Row + 0, 5)
If WorksheetFunction.CountA(wks.Range("f:f")) > 1 Then
If WorksheetFunction.CountA(wks.Range("a:a")) > 1 Then
wks.Range("f:f").AdvancedFilter xlFilterCopy, , r, True
wks.Range("a:a").AdvancedFilter xlFilterCopy, , y, True
Else
r = "N/A"
y = "N/A"
End If
End If
r.Delete xlShiftUp
End If
' I HAVE INSERTED BLOCK ENDINGS FROM HERE, AND CHANGED THE INDENTING OF THE SUBSEQUENT CODE TO FIT
' The next 4 lines are all inserted
End If
End With
End If
End With
' I have removed 4 x 'tab' indents from all of the code below
Next wks
Range("A1").Value = "File Name "
Range("B1").Value = "Sheet Name "
Range("D1").Value = "Scenario Name"
intRow = 2
For i = 1 To Sheets.Count
If Sheets(i).Name <> ActiveSheet.Name Then
Cells(intRow, 2) = Sheets(i).Name
Cells(intRow, 1) = ActiveWorkbook.Name
intRow = intRow + 1
End If
Next i
End Sub
Here is one way to get the column number of a header
Option Explicit
Public Function hdrCol(ByRef ws As Worksheet, _
ByVal hdrName As String, _
Optional hdrRow As Long = 1, _
Optional matchLtrCase As Boolean = True) As Long
Dim found As Range, foundCol As Long
If Not ws Is Nothing Then
hdrRow = Abs(hdrRow)
hdrName = Trim(hdrName)
If hdrRow > 0 And Len(hdrName) > 0 Then
Set found = ws.UsedRange.Rows.Find(What:=hdrName, _
LookIn:=xlFormulas, _
LookAt:=xlWhole, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlNext, _
matchCase:=matchLtrCase)
If Not found Is Nothing Then foundCol = found.Column
End If
End If
hdrCol = foundCol
End Function
To test it:
Public Sub testHeader()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Worksheets
MsgBox hdrCol(ws, "Stackoverflow")
Next
End Sub
.
Edit:
Changes I'd make to your code (not tested)
Option Explicit
Public Sub stkoverflow()
Dim wb As Workbook, ws As Worksheet, wsSummary As Worksheet, lr As Long
Dim y As Range, r As Range, thisRow As Long, colA As Range, colF As Range
Set wb = ActiveWorkbook
For Each ws In wb.Worksheets
lr = ws.Cells(ws.Rows.Count, "C").End(3).Row
With ws.Range("F2:F" & lr)
.ClearContents
.Formula = "=IFERROR(LEFT(E2,FIND(""_"",E2,1)-1),LEFT(E2,2))"
.Value = .Value
End With
ws.Range("F1").Value = "Test"
If ws.Name = "Unique data" Then Set wsSummary = ws
Next ws
If wsSummary Is Nothing Then
Set wsSummary = wb.Worksheets.Add
wsSummary.Name = "Unique data"
End If
For Each ws In wb.Worksheets
With wsSummary
If ws.Name <> .Name Then
'...
'Determine dynamic columns based on header
Set colA = ws.Columns(hdrCol(ws, "YOUR_HEADER_NAME_FOR_COL_A", 1, True))
Set colF = ws.Columns(hdrCol(ws, "YOUR_HEADER_NAME_FOR_COL_F", 1, True))
If ws.Name <> .Name Then
If Application.WorksheetFunction.CountA(colA) Then
Set r = .Cells(.Cells(.Rows.Count, 4).End(xlUp).Row + 1, 4)
Set y = .Cells(.Cells(.Rows.Count, 5).End(xlUp).Row + 0, 5)
If WorksheetFunction.CountA(colF) > 1 Then
If WorksheetFunction.CountA(colA) > 1 Then
colF.AdvancedFilter xlFilterCopy, , r, True
colA.AdvancedFilter xlFilterCopy, , y, True
Else
r = "N/A"
y = "N/A"
End If
End If
r.Delete xlShiftUp
End If
'...
End If
End If
End With
'...
Next ws
With ActiveSheet 'not sure about the ActiveSheet...
.Range("A1").Value = "File Name "
.Range("B1").Value = "Sheet Name "
.Range("D1").Value = "Scenario Name"
End With
thisRow = 2
For Each ws In wb.Worksheets
If ws.Name <> ActiveSheet.Name Then
ActiveSheet.Cells(thisRow, 2) = ws.Name
ActiveSheet.Cells(thisRow, 1) = wb.Name
thisRow = thisRow + 1
End If
Next
End Sub
'---------------------------------------------------------------------------------------