Using VBA to identify ranges based on specific values - excel

This is my first post and I'm kind of a beginner; please be gentle. See this link for a reference of the sheet I'm working with.
My plan is to have B2 contain a drop-down list that will be used to selectively collapse certain row groups to just their heading. I've figured out how to collapse one group with this:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
Set KeyCells = Range("B1")
If Not Application.Intersect(KeyCells, Range(Target.Address)) _
Is Nothing Then
If Range("B1") = "All" Then
Rows("3:6").Select
Selection.EntireRow.Hidden = False
Range("B1").Select
Else
Rows("3:6").Select
Selection.EntireRow.Hidden = True
Range("B1").Select
End If
End If
End Sub
What I don't have is a way to automatically find the groups. If I use a range like Rows("3:6") and someone adds/removes a row, it won't work. (right?)
What I think I need is a way to identify the required ranges by looking at information in the headers. The reference example is blank, but at the "A" column of each grey row will be a number (100, 101, 150, 380, 420A, 420B, 420C, 890). No number will appear twice, and they will appear in numerical order. The "A" column in the white cells under the gray headers will all be blank.
Is there VBA code that will find the locations of the unique headers so I can use their locations to collapse specific groups?
Additional edit to add new screenshots of what I'm hoping to achieve. Person X, Y, Z all have their predetermined grouping they want expanded or collapsed. And I'd probably add an "all" and "none" if I can figure it out. They'll give me that in advance. The numbers on the left won't ever change. It's only a question of whether Person X wants group 120 expanded or collapsed. https://imgur.com/c2lNujn
Edit to show current code:
Public HeaderColor As Long
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Me.HeaderColor = RGB(217, 217, 217)
'If A1 is true, group rows
If Range("A1").Value Then
'Use getRegion function on target
Dim rng As Range
Set rng = getRegion(Target)
'If the returned range is nothing then end sub
If rng Is Nothing Then Exit Sub
'Select region
Application.EnableEvents = False
rng.Select
Application.EnableEvents = True
End If
'If D1 is true, apply Y/N options for selection in C1
If Range("D1").Value Then
Dim rngX As Range, c As Range
Set rngX = Worksheets("Options").Range("A1:N1").Find(Range("C1"), lookat:=xlPart)
If Not rngX Is Nothing Then
'MsgBox Chr(34) & Range("C1").Value & Chr(34) & " found at " & rngX.Address
End If
'Check
' Dim groupcounter As Long
' For groupcounter = 1 To 80
' If Worksheets("Options").Range(rngX.Column, groupcounter + 1) = "Y" Then
' getNthRegion(ActiveSheet, groupcounter).Hidden = True
' ElseIf Worksheets("Options").Range(rng.Column, groupcounter + 1) = "N" Then
' getNthRegion(ActiveSheet, groupcounter).Hidden = False
' End If
' Next groupcounter
End If
End Sub
Sub customiseVisibility(ByVal query As String)
Dim cell As Range
Set cell = OptionsSheet.Range("1:1").Find(query)
Dim offset As Long
offset = 1
While Not IsEmpty(cell.offset(offset))
getNthRegion(MySheet, offset).Hidden = cell.offset(offset).Value = "N"
offset = offset + 1
Wend
End Sub
Private Function getRegion(cell As Range) As Range
Dim formatted As Boolean
Dim cell_start, cell_end As Range
'If cell row is 1 then exit function
If cell.Row <= 1 Then Exit Function
'If cell row count > 1 then use first cell selected
If cell.Rows.Count > 1 Then Set cell = cell.Cells(1, 1)
'If selection is outside of used range, do nothing
If Application.Intersect(cell, cell.Parent.UsedRange) Is Nothing Then Exit Function
'Special condition
If cell.Interior.Color = Me.HeaderColor Then
'Select row below
Set cell = cell.offset(1)
End If
'Get start cell
Set cell_start = cell
While Not cell_start.Interior.Color = Me.HeaderColor And Not Application.Intersect(cell_start, cell.Parent.UsedRange) Is Nothing ' Your gray color
Set cell_start = cell_start.offset(-1)
Wend
'Get end cell
Set cell_end = cell
While Not cell_end.offset(iRowEnd, 0).Interior.Color = Me.HeaderColor And Not Application.Intersect(cell_end, cell.Parent.UsedRange) Is Nothing ' Your gray color
Set cell_end = cell_end.offset(1)
Wend
'Get region
Set getRegion = Range(cell_start.offset(1), cell_end.offset(-1)).EntireRow
End Function
Function getNthRegion(ByVal sheet As Worksheet, ByVal n As Long) As Range
Dim i, counter As Long
For i = 1 To sheet.UsedRange.Rows.Count
If sheet.Cells(i, 1).Interior.Color = HeaderColor Then
counter = counter + 1
End If
If counter = n Then
Set getNthRegion = getRegion(sheet.Cells(i, 1))
Exit Function
End If
Next
End Function

Could you abuse your formatting?
Here is tested code:
Public HeaderColor as Long
Private OptionsSheet as Worksheet
Private DataSheet as Worksheet
Private Sub Worksheet_Change(ByVal Target As Range)
Me.HeaderColor = RGB(217, 217, 217)
set OptionsSheet = sheets("Options")
set DataSheet = ActiveWorksheet
if target.address = "$B$1" then
customiseVisibility target.value
end if
End Sub
Sub customiseVisibility(ByVal query As String)
Dim cell As Range
Set cell = OptionsSheet.Range("1:1").Find(query)
Dim offset As Long
offset = 1
While Not IsEmpty(cell.offset(offset))
getNthRegion(DataSheet, offset).Hidden = cell.offset(offset).Value = "N"
offset = offset + 1
Wend
End Sub
Private Function getRegion(cell As Range) As Range
Dim formatted As Boolean
Dim cell_start, cell_end As Range
'If cell row is 1 then exit function
If cell.Row <= 1 Then Exit Function
'If cell row count > 1 then use first cell selected
If cell.Rows.Count > 1 Then Set cell = cell.Cells(1, 1)
'If selection is outside of used range, do nothing
If Application.Intersect(cell, cell.Parent.UsedRange) Is Nothing Then Exit Function
'Special condition
If cell.Interior.Color = Me.HeaderColor Then
'Select row below
Set cell = cell.offset(1)
End If
'Get start cell
Set cell_start = cell
While Not cell_start.Interior.Color = Me.HeaderColor And Not Application.Intersect(cell_start, cell.Parent.UsedRange) Is Nothing ' Your gray color
Set cell_start = cell_start.offset(-1)
Wend
'Get end cell
Set cell_end = cell
While Not cell_end.offset(iRowEnd, 0).Interior.Color = Me.HeaderColor And Not Application.Intersect(cell_end, cell.Parent.UsedRange) Is Nothing ' Your gray color
Set cell_end = cell_end.offset(1)
Wend
'Get region
Set getRegion = Range(cell_start.offset(1), cell_end.offset(-1)).EntireRow
End Function
Function getNthRegion(ByVal sheet As Worksheet, ByVal n As Long) As Range
Dim i, counter As Long
For i = 1 To sheet.UsedRange.Rows.Count
If sheet.Cells(i, 1).Interior.Color = HeaderColor Then
counter = counter + 1
End If
If counter = n Then
Set getNthRegion = getRegion(sheet.Cells(i, 1))
Exit Function
End If
Next
End Function
Note:
This question is really really specific. Next time try to break your problem down into smaller chunks and take on 1 question at a time (if anything). Also I strongly recommend including example data to work off of. E.G.
| Number | All | PersonA | PersonB | ...
-----------------------------------------
| 1 | N | Y | N | ...
| 2 | N | Y | N | ...
| 3 | N | Y | N | ...
| 4 | N | Y | Y | ...
| 5 | N | N | N | ...
| 6 | N | N | Y | ...
| 7 | N | N | N | ...
| 8 | N | N | Y | ...

As #BigBen suggested - use FIND and then Group between the headers - one row down from Start and one row up from End.
Public Sub CreateOutline()
Dim sFirstAdd As String
Dim rFound As Range
Dim rStart As Range
Dim rEnd As Range
With ThisWorkbook.Worksheets("Sheet1")
.Cells.ClearOutline 'Remove any existing.
With .Cells.EntireColumn
Set rFound = .Find(What:="*", _
After:=.Cells(1, 1), _
LookIn:=xlValues, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext)
If Not rFound Is Nothing Then
sFirstAdd = rFound.Address
Do
Set rStart = rFound
Set rFound = .FindNext(rFound)
Set rEnd = rFound
Range(rStart.Offset(1), rEnd.Offset(-1)).Rows.Group
'Include a marker to state where the end of the last section is.
'Otherwise the last section will go from cell A1 to just below last section header.
If rEnd = "End" Then sFirstAdd = rFound.Address
Loop While rFound.Address <> sFirstAdd
End If
End With
End With
End Sub

Instead of hiding and unhiding rows, you can use the Outline.ShowLevels method to collapse the grouping.
So something like this to:
Test if B1 changed.
Find the corresponding header in the first column.
If there's a match, test if the next row has a grouping (OutlineLevel > 1).
If so, ShowDetail = False for that row.
Note that the use of On Error Resume Next is discouraged. However .ShowDetail = False threw an error when the specified group was already collapsed. As I investigate further, this is the quick fix.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Me.Range("B1"), Target) Is Nothing Then
With Me
Dim rng As Range
Set rng = .Columns(1).Find(.Range("B1").Value)
If Not rng Is Nothing Then
With rng.Offset(1).EntireRow
On Error Resume Next
If .OutlineLevel > 1 Then .ShowDetail = False
End With
End If
End With
End If
End Sub

Related

How to change cell value based on input number

I want to fill the cells with Character Abbreviation, according to the entering number in that cell.
For example I created the following image Where the Column L should be filled with DM, AG, IW, WSW, CW. For this purpose, I used numeric values from 1 to 5 (DM=1, AG=2, IW=3, WSW=4, CW=5). I already
For this, I already entered those values (AR6:AW17) as following in the same sheet.
Tried
I used the following code :
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("L:L")) Is Nothing Then Exit Sub
Application.ScreenUpdating = False
Dim foundVal As Range
Set foundVal = Range("AR5:AV5").Find(Target, LookIn:=xlValues, lookat:=xlWhole)
If Not foundVal Is Nothing Then
Target = foundVal.Offset(1, 0)
End If
Application.ScreenUpdating = True
End Sub
Problem
My question is how can I extend this to put the values to
Column L as AR6:AV6
Column M as AR7:AW7
Column P as AR8:AV8
Column Q as AR14:AU14
Column T as AR15:AV15
Column W as AR17:AU17
Updated
The column Q, T, W are added for more consideration please.
and so on, please?
Resize and Offset in Worksheet Change
Adjust the values in the constants section.
The Code
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Const ColRangesList As String = "L,M,N,P"
Const RowRangesList As String = "AR5:AV5,AR6:AW6,AR7:AS7;AT8:AX8"
Const RowOffset As Long = 1
Const ColOffset As Long = 0
If Target.Cells.CountLarge = 1 Then
Dim ColRanges() As String: ColRanges = Split(ColRangesList, ",")
Dim RowRanges() As String: RowRanges = Split(RowRangesList, ",")
Dim crg As Range, rrg As Range, cel As Range
Dim n As Long
For n = 0 To UBound(ColRanges)
Set crg = Columns(ColRanges(n))
Set rrg = Range(RowRanges(n))
If Not Intersect(Target, crg) Is Nothing Then
Set cel = rrg.Find(Target.Value, rrg.Cells(rrg.Cells.Count), _
LookIn:=xlFormulas, LookAt:=xlWhole)
If Not cel Is Nothing Then
Application.ScreenUpdating = False
Application.EnableEvents = False
Target.Value = cel.Offset(RowOffset, ColOffset).Value
Application.EnableEvents = True
Application.ScreenUpdating = True
Exit For
End If
End If
Next n
End If
End Sub

Change color of text in a cell of excel

I would like to change the color of a text in a cell in MS Excel like the conditioned formatting. I have different text in one cell, e.g. "WUG-FGT" or "INZL-DRE". I would like to format the cells (all cells in my workshhet), that a defined text like "WUG-FGT" appears red and the other text "INZL-DRE" green, but the text is in the same cell. With "sandard" conditioned formatting I only get the backgroud coloured.
A similar questions is this: How can I change color of text in a cell of MS Excel?
But the difference is that I (actually) don't work with programming. That means that I need a more simple or easy solution to implement this in my excel file.
Is this possible? A solution with VBA would also be possible, I know how to implement them.
here example how you can achieve required results:
Sub test()
Dim cl As Range
Dim sVar1$, sVar2$, pos%
sVar1 = "WUG-FGT"
sVar2 = "INZL-DRE"
For Each cl In Selection
If cl.Value2 Like "*" & sVar1 & "*" Then
pos = InStr(1, cl.Value2, sVar1, vbTextCompare)
cl.Characters(pos, Len(sVar1)).Font.Color = vbRed
End If
If cl.Value2 Like "*" & sVar2 & "*" Then
pos = InStr(1, cl.Value2, sVar2, vbTextCompare)
cl.Characters(pos, Len(sVar2)).Font.Color = vbGreen
End If
Next cl
End Sub
test
UPDATE
Is it possible to count how often the word has been detected. Either to write to total amount to a defined cell or what also would be great, to add the number of counts in brackets behind the word with an control variable? So in your example: A2: "WUG-FGT(1)", A4: "WUG-FGT(2)", A5: "WUG-FGT(3)"
Yes, but you should update the cell before colorizing, otherwise whole cell font will be colorized by the first char's color (e.g. cell contains both keywords and first is red, and second is green, after update whole cell font will be red). See updated code and test bellow:
Sub test_upd()
Dim cl As Range, sVar1$, sVar2$, pos%, cnt1%, cnt2%
Dim bVar1 As Boolean, bVar2 As Boolean
sVar1 = "WUG-FGT": cnt1 = 0
sVar2 = "INZL-DRE": cnt2 = 0
For Each cl In Selection
'string value should be updated before colorize
If cl.Value2 Like "*" & sVar1 & "*" Then
bVar1 = True
cnt1 = cnt1 + 1
cl.Value2 = Replace(cl.Value, sVar1, sVar1 & "(" & cnt1 & ")")
End If
If cl.Value2 Like "*" & sVar2 & "*" Then
bVar2 = True
cnt2 = cnt2 + 1
cl.Value2 = Replace(cl.Value, sVar2, sVar2 & "(" & cnt2 & ")")
End If
pos = InStr(1, cl.Value2, sVar1, vbTextCompare)
If bVar1 Then cl.Characters(pos, Len(sVar1)).Font.Color = vbRed
pos = InStr(1, cl.Value2, sVar2, vbTextCompare)
If bVar2 Then cl.Characters(pos, Len(sVar2)).Font.Color = vbGreen
bVar1 = False: bVar2 = False
Next cl
End Sub
test
Change Format of Parts of Values in Cells
Links
Workbook Download
Image
The Code
'*******************************************************************************
Sub CFF(Range As Range, SearchString As String, _
Optional ColorIndex As Long = -4105, _
Optional OccurrenceFirst0All1 As Long = 1, _
Optional Case1In0Sensitive As Long = 1)
' ColorIndex
' 3 for Red
' 10 for Green
' OccurrenceFirst0All1
' 0 - Only First Occurrence of SearchString in cell of Range.
' 1 (Default) - All occurrences of SearchString in cell of Range.
' Case1In0Sensitive
' 0 - Case-sensitive i.e. aaa <> AaA <> AAA
' 1 (Default) - Case-INsensitive i.e. aaa = AaA = AAA
Const cBold As Boolean = False ' Enable Bold (True) for ColorIndex <> -4105
Dim i As Long ' Row Counter
Dim j As Long ' Column Counter
Dim rngCell As Range ' Current Cell Range
Dim lngStart As Long ' Current Start Position
Dim lngChars As Long ' Number of characters (Length) of SearchString
' Assign Length of SearchString to variable.
lngChars = Len(SearchString)
' In Range.
With Range
' Loop through rows of Range.
For i = .Row To .Row + .Rows.Count - 1
' Loop through columns of Range.
For j = .Column To .Column + .Columns.Count - 1
' Assign current cell range to variable.
Set rngCell = .Cells(i, j)
' Calculate the position of the first occurrence
' of SearchString in value of current cell range.
lngStart = InStr(1, rngCell, SearchString, Case1In0Sensitive)
If lngStart > 0 Then ' SearchString IS found.
If OccurrenceFirst0All1 = 0 Then ' FIRST occurrence only.
GoSub ChangeFontFormat
Else ' ALL occurrences.
Do
GoSub ChangeFontFormat
lngStart = lngStart + lngChars
lngStart = InStr(lngStart, rngCell, SearchString, _
Case1In0Sensitive)
Loop Until lngStart = 0
End If
'Else ' SearchString NOT found.
End If
Next
Next
End With
Exit Sub
ChangeFontFormat:
' Font Formatting Options
With rngCell.Characters(lngStart, lngChars).Font
' Change font color.
.ColorIndex = ColorIndex
' Enable Bold for ColorIndex <> -4105
If cBold Then
If .ColorIndex = -4105 Then ' -4105 = xlAutomatic
.Bold = False
Else
.Bold = True
End If
End If
End With
Return
End Sub
'*******************************************************************************
Real Used Range (RUR)
'*******************************************************************************
' Purpose: Returns the Real Used Range of a worksheet.
' Returns: Range Object or "Nothing".
'*******************************************************************************
Function RUR(Optional NotActiveSheet As Worksheet) As Range
Dim objWs As Worksheet
If Not NotActiveSheet Is Nothing Then
Set objWs = NotActiveSheet
Else
Set objWs = ActiveSheet
End If
If objWs Is Nothing Then Exit Function
Dim HLP As Range ' Cells Range
Dim FUR As Long ' First Used Row Number
Dim FUC As Long ' First Used Column Number
Dim LUR As Long ' Last Used Row Number
Dim LUC As Long ' Last Used Column Number
With objWs.Cells
Set HLP = .Cells(.Cells.Count)
Set RUR = .Find("*", HLP, xlFormulas, xlWhole, xlByRows)
If Not RUR Is Nothing Then
FUR = RUR.Row
FUC = .Find("*", HLP, , , xlByColumns).Column
LUR = .Find("*", , , , xlByRows, xlPrevious).Row
LUC = .Find("*", , , , xlByColumns, xlPrevious).Column
Set RUR = .Cells(FUR, FUC) _
.Resize(LUR - FUR + 1, LUC - FUC + 1)
End If
End With
End Function
'*******************************************************************************
Usage
The following code if used with the Change1Reset0 argument set to 1, will change the format in each occurrence of the desired strings in a case-INsensitive search.
'*******************************************************************************
Sub ChangeStringFormat(Optional Change1Reset0 As Long = 0)
Const cSheet As Variant = "Sheet1"
Const cStringList As String = "WUG-FGT,INZL-DRE"
Const cColorIndexList As String = "3,10" ' 3-Red, 10-Green
' Note: More strings can be added to cStringList but then there have to be
' added more ColorIndex values to cColorIndexList i.e. the number of
' elements in cStringList has to be equal to the number of elements
' in cColorIndexList.
Dim rng As Range ' Range
Dim vntS As Variant ' String Array
Dim vntC As Variant ' Color IndexArray
Dim i As Long ' Array Elements Counter
Set rng = RUR(ThisWorkbook.Worksheets(cSheet))
If Not rng Is Nothing Then
vntS = Split(cStringList, ",")
If Change1Reset0 = 1 Then
vntC = Split(cColorIndexList, ",")
' Loop through elements of String (ColorIndex) Array
For i = 0 To UBound(vntS)
' Change Font Format.
CFF rng, CStr(Trim(vntS(i))), CLng(Trim(vntC(i)))
Next
Else
For i = 0 To UBound(vntS)
' Reset Font Format.
CFF rng, CStr(Trim(vntS(i)))
Next
End If
End If
End Sub
'*******************************************************************************
The previous codes should all be in a standard module e.g. Module1.
CommandButtons
The following code should be in the sheet window where the commandbuttons are created, e.g. Sheet1.
Option Explicit
Private Sub cmdChange_Click()
ChangeStringFormat 1
End Sub
Private Sub cmdReset_Click()
ChangeStringFormat ' or ChangeStringFormat 0
End Sub
Try:
Option Explicit
Sub test()
Dim rng As Range, cell As Range
Dim StartPosWUG As Long, StartPosINL As Long
With ThisWorkbook.Worksheets("Sheet1")
Set rng = .UsedRange
For Each cell In rng
StartPosWUG = InStr(1, cell, "WUG-FGT")
StartPosINL = InStr(1, cell, "INZL-DRE")
If StartPosWUG > 0 Then
With cell.Characters(Start:=StartPosWUG, Length:=Len("WUG-FGT")).Font
.Color = vbRed
End With
End If
If StartPosINL > 0 Then
With cell.Characters(Start:=StartPosINL, Length:=Len("INZL-DRE")).Font
.Color = vbGreen
End With
End If
Next
End With
End Sub

finding duplicate values from two sheets

I have Excel two sheets
data like these....
sheet1: 2000, 3000, 4500, 300, 2000, 3000
sheet 2: 300, 2000, 3000, 4550
i run the following code to highlight the values in both sheets with different colors, where value meets with criteria.
but problem is values of sheet1 all 2000, 3000 filled with colors, whereas sheet2 having 2000, 3000 only one time.
if compare with sheet 2 it contains values 2000, 3000 only one time
so sheet1 values first and second fill with colors, rest of values (last two values) should not be in color.
great thanks for solution.
Sub Dupranges()
Dim wr1 As Range, wr2 As Range, Rng1 As Range, Rng2 As Range
Set wr1 = Worksheets("Sheet1").Range("f1:f10")
Set wr2 = Worksheets("Sheet2").Range("g1:g10")
For Each Rng1 In wr1
Rng1.Value = Rng1.Value
For Each Rng2 In wr2
If Rng1.Value = Rng2.Value Then
Rng1.Interior.ColorIndex = 43
Rng2.Interior.ColorIndex = 33
Exit For
End If
Next
Next
MsgBox "Successfully completed"
End Sub
i think i got what you wanted, its not pretty but i have just started the vba.
You have to change the range back to yours
Sub format()
Dim wr1 As Range, wr2 As Range
Set wr1 = Worksheets("Sheet1").Range("a1:a10")
Set wr2 = Worksheets("Sheet2").Range("a1:a10")
For i = 1 To wr1.Count
check_value = wr1.Item(i)
For k = 1 To wr2.Count
check_value2 = wr2.Item(k)
If (check_value = check_value2) And (wr2.Item(k).Interior.ColorIndex = 33) And
(wr1.Item(i).Interior.ColorIndex = 43) Then
Else
If (check_value = check_value2) And (wr2.Item(k).Interior.ColorIndex <> 33) And
(wr1.Item(i).Interior.ColorIndex <> 43) And (wr2.Item(k).Value > "") Then
wr1.Item(i).Interior.ColorIndex = 43
wr2.Item(k).Interior.ColorIndex = 33
Exit For
End If
End If
Next
Next
MsgBox "Successfully completed"
End Sub
Hopefully you find this usefully
Your code is nearly ok, but you can save time moving ranges to arrays.
Option Explicit
Sub showDupes(src As Range, tgt As Range)
Dim c As Range, i As Long, srcVal
Dim a As Variant, found As Boolean
a = tgt.Value2 'store tgt into array for speed
For Each c In src
srcVal = c.Value2
found = False
For i = 1 To UBound(a)
If a(i, 1) = srcVal Then
found = True
Exit For
End If
Next i
If found Then
'highlight in src
c.Interior.ColorIndex = 43
'highlight in tgt
tgt.Cells(i, 1).Interior.ColorIndex = 43
End If
Next c
End Sub
Sub showDupes_test()
showDupes Sheet1.Range("B4").CurrentRegion, Sheet2.Range("b4").CurrentRegion
End Sub
Note that in this version, if tgt has local duplicates, only the first one will be highlighted.

VBA Excel Merging of Cells based on a Specific cell value

I would like to automate the merging of cells based by column for multiple columns based on the information in a specific column.
Based on the below picture the values in column c will determine the number of rows that need to be merged together for Columns A through K. With each change in the value in Column C - the merging would begin again.
Private Sub MergeCells_C()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Dim rngMerge As Range, cell As Range
Set rngMerge = Range("C1:C1000") 'Set the range limits here
MergeAgain:
For Each cell In rngMerge
If cell.Value = cell.Offset(1, 0).Value And IsEmpty(cell) = False Then
Range(cell, cell.Offset(1, 0)).Merge
GoTo MergeAgain
End If
Next
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
This worked for me:
Sub MergeCellsByC()
Dim c As Range, sht As Worksheet, currV
Dim n As Long, rw As Range, r As Range
Set sht = ActiveSheet
Set c = sht.Range("C4") 'adjust to suit....
currV = Chr(0) 'start with a dummy value
Do
If c.Value <> currV Then
If n > 1 Then
Set rw = c.EntireRow.Range("A1:K1") 'A1:K1 relative to the row we're on...
Application.DisplayAlerts = False
'loop across the row and merge the cells above
For Each r In rw.Cells
r.Offset(-n).Resize(n).Merge
Next r
Application.DisplayAlerts = True
End If
currV = c.Value
n = 1
Else
n = n + 1 'increment count for this value
End If
If Len(c.Value) = 0 Then Exit Do 'exit on first empty cell
Set c = c.Offset(1, 0) 'next row down
Loop
End Sub

Find duplicates in a column and add their corresponding values from another column

I have column A with staff ids and hours worked in column K.
I would like if a staff id appears more than once to add hours worked and put the result in another column corresponding to the first instance of that staff id and the duplicates being 0.
This is for a monthly report and there may be over 2k records at any point.
As everyone else said, a Pivot Table really is the best way. If you're unsure how to use a PivotTable or what it's good for, refer to this SO post where I explain in detail.
Anyway, I put together the below VBA function to help get you started. It's by no means the most efficient approach; it also makes the following assumptions:
Sheet 1 has all the data
A has Staff Id
B has Hours
C is reserved for Total Hours
D will be available for processing status output
This of course can all be changed very easily by altering the code a bit. Review the code, it's commented for you to understand.
The reason a Status column must exist is to avoid processing a Staff Id that was already processed. You could very alter the code to avoid the need for this column, but this is the way I went about things.
CODE
Public Sub HoursForEmployeeById()
Dim currentStaffId As String
Dim totalHours As Double
Dim totalStaffRows As Integer
Dim currentStaffRow As Integer
Dim totalSearchRows As Integer
Dim currentSearchRow As Integer
Dim staffColumn As Integer
Dim hoursColumn As Integer
Dim totalHoursColumn As Integer
Dim statusColumn As Integer
'change these to appropriate columns
staffColumn = 1
hoursColumn = 2
totalHoursColumn = 3
statusColumn = 4
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
totalStaffRows = Sheet1.Cells(Rows.Count, staffColumn).End(xlUp).Row
For currentStaffRow = 2 To totalStaffRows
currentStaffId = Cells(currentStaffRow, staffColumn).Value
'if the current staff Id was not already processed (duplicate record)
If Not StrComp("Duplicate", Cells(currentStaffRow, statusColumn).Value, vbTextCompare) = 0 Then
'get this rows total hours
totalHours = CDbl(Cells(currentStaffRow, hoursColumn).Value)
'search all subsequent rows for duplicates
totalSearchRows = totalStaffRows - currentStaffRow + 1
For currentSearchRow = currentStaffRow + 1 To totalSearchRows
If StrComp(currentStaffId, Cells(currentSearchRow, staffColumn), vbTextCompare) = 0 Then
'duplicate found: log the hours worked, set them to 0, then mark as Duplicate
totalHours = totalHours + CDbl(Cells(currentSearchRow, hoursColumn).Value)
Cells(currentSearchRow, hoursColumn).Value = 0
Cells(currentSearchRow, statusColumn).Value = "Duplicate"
End If
Next
'output total hours worked and mark as Processed
Cells(currentStaffRow, totalHoursColumn).Value = totalHours
Cells(currentStaffRow, statusColumn).Value = "Processed"
totalHours = 0 'reset total hours worked
End If
Next
Application.ScreenUpdating = False
Application.Calculation = xlCalculationAutomatic
End Sub
BEFORE
AFTER
Here is the solution for the data table located in range A1:B10 with headers and results written to column C.
Sub Solution()
Range("c2:c10").Clear
Dim i
For i = 2 To 10
If WorksheetFunction.SumIf(Range("A1:a10"), Cells(i, 1), Range("C1:C10")) = 0 Then
Cells(i, "c") = WorksheetFunction.SumIf( _
Range("A1:a10"), Cells(i, 1), Range("B1:B10"))
Else
Cells(i, "c") = 0
End If
Next i
End Sub
Try below code :
Sub sample()
Dim lastRow As Integer, num As Integer, i As Integer
lastRow = Range("A65000").End(xlUp).Row
For i = 2 To lastRow
num = WorksheetFunction.Match(Cells(i, 1), Range("A1:A" & lastRow), 0)
If i = num Then
Cells(i, 3) = WorksheetFunction.SumIf(Range("A1:A" & lastRow), Cells(i, 1), Range("B1:B" & lastRow))
Else
Cells(i, 1).Interior.Color = vbYellow
End If
Next
End Sub
BEFORE
AFTER
Below code identifies duplicate value in a column and highlight with red. Hope this might be of some help.
iLastRow = Cells(chosenExcelSheet.Rows.Count, 1).End(xlUp).Row 'Determine the last row to look at
Set rangeLocation = Range("A1:A" & iLastRow)
'Checking if duplicate values exists in same column
For Each myCell In rangeLocation
If WorksheetFunction.CountIf(rangeLocation, myCell.Value) > 1 Then
myCell.Interior.ColorIndex = 3'Highlight with red Color
Else
myCell.Interior.ColorIndex = 2'Retain white Color
End If
Next
Sub SelectColoredCells()
Dim rCell As Range
Dim lColor As Long
Dim rColored As Range
'Select the color by name (8 possible)
'vbBlack, vbBlue, vbGreen, vbCyan,
'vbRed, vbMagenta, vbYellow, vbWhite
lColor = RGB(156, 0, 6)
'If you prefer, you can use the RGB function
'to specify a color
'Default was lColor = vbBlue
'lColor = RGB(0, 0, 255)
Set rColored = Nothing
For Each rCell In Selection
If rCell.Interior.Color = lColor Then
If rColored Is Nothing Then
Set rColored = rCell
Else
Set rColored = Union(rColored, rCell)
End If
End If
Next
If rColored Is Nothing Then
MsgBox "No cells match the color"
Else
rColored.Select
MsgBox "Selected cells match the color:" & _
vbCrLf & rColored.Address
End If
Set rCell = Nothing
Set rColored = Nothing
End Sub
this highlights the duplicates

Resources