Delete rows from sheet where match is found in excel - excel

I have an excel sheet which has just over a thousand lines and I need to be delete all ROWS in it which are as follows:
column A, B,C,D,E,F AND G MUST be an exact match.
Column H (hours) must have a negative value which matches the same value but positive forming a pair, then the pair is deleted.
so the following is an example of a match:
date prod Item Title Code person number hours
2016 xxx 123 test a12d John Smith 78901 8
2016 xxx 123 test a12d John Smith 78901 -8
2016 xxx 123 test a12d John Smith 78901 -8
2016 xxx 123 test a12d John Smith 78901 -42
resulting in:
date prod Item Title Code person number hours
2016 xxx 123 test a12d John Smith 78901 -8
2016 xxx 123 test a12d John Smith 78901 -42
I'm having trouble explaining it let alone writing a macro!
Dim LR As Long
Dim i As Long
'Remove rows
LR = Range("H" & Rows.Count).End(xlUp).Row
For i = LR To 1 Step -1
'How do i compare it against other rows?
Next i

One way to do this would be to join all of the columns together using a delimiter and add it to a dictionary as the key. This will only hold unique values. You could then split each one back into columns again and overwrite the whole sheet. There wold be many other ways to achieve this though and this is just an example of one way you could do it. Also, as always if you do try this try it first on a copy of your original data in case of any unexpected behaviour
Option Explicit
Public Sub ExampleRemoveDuplicates()
Dim dict As Object
Dim temp As String
Dim calc As String
Dim headers As Variant
Dim NoCol As Long, i As Long, j As Long
Dim c, key
With Application
.ScreenUpdating = False
calc = .Calculation
.Calculation = xlCalculationManual
End With
Set dict = CreateObject("Scripting.Dictionary")
' Change this to the sheet that is applicable
With Sheet1
NoCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
' Assumes first row of sheet is headers
headers = .Range(.Cells(1, 1), .Cells(1, NoCol)).Value2
For Each c In .Range(.Cells(2, 1), .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, 1))
ReDim arr(1 To NoCol)
temp = vbNullString
j = 1
Do
arr(j) = c.Offset(0, j - 1).Value2
If j = 8 Then
temp = temp & Abs(arr(j))
Else
temp = temp & arr(j)
End If
j = j + 1
Loop Until j = NoCol + 1
If Not dict.exists(temp) And Not temp = vbNullString Then dict.Add key:=temp, Item:=arr
Next c
.Cells.ClearContents
.Range(.Cells(1, 1), .Cells(1, NoCol)).Value2 = headers
i = 1
ReDim Results(1 To dict.Count, 1 To NoCol)
For Each key In dict.keys
For j = 1 To NoCol
Results(i, j) = dict(key)(j)
Next j
i = i + 1
Next key
With .Cells(1, 1)
.Range(.Offset(1, 0), .Offset(dict.Count, NoCol - 1)) = Results
End With
End With
With Application
.Calculation = calc
.ScreenUpdating = True
End With
End Sub

I think (meaning I didn't test :-)) this should do the job.
Option Explicit
Sub DeleteMatchingRow()
' 30 Mar 2017
Dim Rl As Long
Dim R As Long
Application.ScreenUpdating = False
With ActiveSheet
Rl = .Range("H" & .Rows.Count).End(xlUp).Row
For R = Rl To 2 Step -1
If FindMatch(CompString(.Rows(R)), Val(.Cells(R, 8).Value), R) Then
.Rows(R).EntireRow.Delete
End If
Next R
End With
Application.ScreenUpdating = Treu
End Sub
Private Function FindMatch(ByVal Comp1 As String, _
ByVal Gval As Integer, _
ByVal LR As Long) As Long
' 30 Mar 2017
' return the row number where a match was found
' or return 0, if no match was found
Dim R As Long
Dim Comp2 As String
With ActiveSheet
For R = LR To 1 Step -1
Comp2 = CompString(.Rows(R))
If StrComp(Comp1, Comp2, vbBinaryCompare) = 0 Then
If .Cells(R, 8).Value = (Gval * -1) Then
FindMatch = R
Exit Function
End If
End If
Next R
End With
End Function
Private Function CompString(Row As Range) As String
' 30 Mar 2017
Dim Fun As String
Dim C As Long
With Row
For C = 1 To 7
Fun = Fun & CStr(.Cells(C).Value)
Next C
End With
CompString = Fun
End Function
The code prepares two strings consisting of A+B+C+D+E+F (all as strings, not numbers) and compares them. If they are identical, the value in column G is compares with its pendent in the match row * -1. If the two values are identical the row is identified as a match.
The function CompString prepares the comparison strings. The function FindMatch finds the match, and the main routine DeleteMatchingRow does the deleting. I don't have the data to test it on, but in theory it sounds good, doesn't it?
You can use the following function to get a visual of rows which you consider matching but the code doesn't.
Private Sub TestMatch()
' 31 Mar 2017
Dim R As Long
R = 3
With ActiveSheet
Debug.Print CompString(.Rows(R)), "Column G has "; .Cells(R, 8).Value
End With
End Sub
Paste this code in the same code sheet as the function CompString. Make sure that the sheet from which you want to read a line is active (look at it before switching to the VBE window). Replace the value 3 in the code with the number of the row you wish to read. The compare string will be printed in the VB Editor's Immediate Window (press Ctl+G if you don't see it). Repeat the exercise with the other string. You can then compare them visually and determine why VBA considers them different.

Related

Subscript out of range (Extract substrings from multiple comma separated strings macro in Excel)

I have the following list on Sheet1:
COLUMN A COLUMNB COLUMN C
1 ADDRESS Services(s) USED VEHICLE(S) USED
2 Address1 Service4 Vehicle1, Vehicle3, Vehicle4
3 Address1 Service3 Vehicle1, Vehicle3, Vehicle4
4 Address2 Service5 Vehicle1, Vehicle2, Vehicle5
5 Address2 Service2 Vehicle1, Vehicle6
6 Address2 Service1, Service2, Service3, Service4, Service5, Service6 Vehicle2, Vehicle5, Vehicle6
7 Address1 Service1, Service2, Service3, Service4, Service5, Service6 Vehicle2, Vehicle3
On Sheet2, I would like the following output in Column B when I enter "Address1" in cell B4
COLUMN A COLUMN B
4 Address1
12 Service1
13 Service2
14 Service3
15 Service4
16 Service5
17 Service6
50 Vehicle1
51 Vehicle2
52 Vehicle3
53 Vehicle4
54 Vehicle5
56 Vehicle6
Worksheet_Change Code ("Sheet2" module)
Private Sub Worksheet_Change(ByVal Target As Range)
' call Function only if modifed cell is in Column "B"
If Not Intersect(Target, Range("B4")) Is Nothing Then
Application.EnableEvents = False
Call FilterAddress(Target.Value)
End If
Application.EnableEvents = True
End Sub
Sub FilterAddress Code (Regular module)
Option Explicit
Sub FilterAddress(FilterVal As String)
Dim LastRow As Long
Dim FilterRng As Range, cell As Range
Dim Dict As Object
'Dim ID
Dim Vehicle As Variant
Dim VehicleArr As Variant
Dim i As Long, j As Long
Dim Service As Variant
Dim ServiceArr As Variant
Dim x As Long, y As Long
Dim My_Range As Range
With Sheets("Sheet1")
' find last row with data in column "A" (Adress)
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set FilterRng = .Range("A1:C" & LastRow)
.Range("A1").AutoFilter
' AutoFilter "Sheet1" according to value in "Sheet2" in Column B
FilterRng.AutoFilter Field:=1, Criteria1:=FilterVal
Set Dict = CreateObject("Scripting.Dictionary")
' create an array with size up to number of rows >> will resize it later
ReDim ServiceArr(1 To LastRow)
j = 1 ' init array counter
For Each cell In .Range("B2:B" & LastRow).SpecialCells(xlCellTypeVisible)
' read values from cell to array using the Split function
Service = Split(cell.Value, ",")
For i = LBound(Service) To UBound(Service)
Service(i) = Trim(Service(i)) ' remove extra spaces from string
If Not Dict.exists(Service(i)) Then
Dict.Add Service(i), Service(i)
' save Service Name to array >> will use it later for "Bubble-sort" and paste in "Sheet2"
ServiceArr(j) = Service(i)
j = j + 1 ' increment ServiceArr counter
End If
Next i
Next cell
' resize array up to number of actual Service
ReDim Preserve ServiceArr(1 To j - 1)
End With
Dim ServiceTmp As Variant
' Bubble-sort Service Array >> sorts the Service array from smallest to largest
For i = 1 To UBound(ServiceArr) - 1
For j = i + 1 To UBound(ServiceArr)
If ServiceArr(j) < ServiceArr(i) Then
ServiceTmp = ServiceArr(j)
ServiceArr(j) = ServiceArr(i)
ServiceArr(i) = ServiceTmp
End If
Next j
Next i
' now the "fun" part >> paste to "Sheet2"
With Sheets("Sheet2")
.Range("A1").Value = "ADDRESS"
.Range("B4").Value = FilterVal
.Range("C1").Value = "VEHICLE(S) USED"
' clear contents from previous run
.Range("B12:B17").ClearContents
.Range("B12:B" & UBound(ServiceArr) + 11) = WorksheetFunction.Transpose(ServiceArr)
End With
FilterRng.Parent.AutoFilterMode = False
With Sheets("Sheet1")
' find last row with data in column "A" (Adress)
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
Set FilterRng = .Range("A1:C" & LastRow)
.Range("A1").AutoFilter
' AutoFilter "Sheet1" according to value in "Sheet2" in Column B
FilterRng.AutoFilter Field:=1, Criteria1:=FilterVal
Set Dict = CreateObject("Scripting.Dictionary")
' create an array with size up to number of rows >> will resize it later
ReDim VehicleArr(1 To LastRow)
y = 1 ' init array counter
For Each cell In .Range("C2:C" & LastRow).SpecialCells(xlCellTypeVisible)
' read values from cell to array using the Split function
Vehicle = Split(cell.Value, ",")
For x = LBound(Vehicle) To UBound(Vehicle)
Vehicle(x) = Trim(Vehicle(x)) ' remove extra spaces from string
If Not Dict.exists(Vehicle(x)) Then
Dict.Add Vehicle(x), Vehicle(x)
' save Vehicle Name to array >> will use it later for "Bubble-sort" and paste in "Sheet2"
VehicleArr(y) = Vehicle(x)
y = y + 1 ' increment VehicleArr counter
End If
Next x
Next cell
' resize array up to number of actual Vehicle
ReDim Preserve VehicleArr(1 To y - 1)
End With
Dim VehicleTmp As Variant
' Bubble-sort Vehicle Array >> sorts the Vehicle array from smallest to largest
For x = 1 To UBound(VehicleArr) - 1
For y = x + 1 To UBound(VehicleArr)
If VehicleArr(y) < VehicleArr(x) Then
VehicleTmp = VehicleArr(y)
VehicleArr(y) = VehicleArr(x)
VehicleArr(x) = VehicleTmp
End If
Next y
Next x
' now the "fun" part >> paste to "Sheet2"
With Sheets("Sheet2")
.Range("A1").Value = "ADDRESS"
.Range("B4").Value = FilterVal
.Range("C1").Value = "VEHICLE(S) USED"
' clear contents from previous run
.Range("B50:B55").ClearContents
.Range("B50:B" & UBound(VehicleArr) + 49) = WorksheetFunction.Transpose(VehicleArr)
End With
FilterRng.Parent.AutoFilterMode = False
End Sub
When I enter "Address1" in cell B4 on Sheet2, I receive the following error:
Runtime error '9':
Subscript out of range
However, if I save the file with B4 populated and close it, then re open the file, I am able to get the macro to work properly when I edit the cell contents to say either Address1 or Address2.
What is causing the "Subscript out of range" message to appear, and how can I change the code to avoid it? Do I need to update the code in Worksheet_Change Code?
I've also noticed that if I delete the contents of cell B4 on Sheet2 I get the following error:
Run-time error'1004':
No cells were found.
Are these two errors related?
The maximum 'j' isn't bounded by the number of rows on the sheet - it's bounded by the number of elements that you can split out of those rows. There's no way to determine before your code executes what size ServiceArr needs to be dimensioned to. That means depending on the data, you'll get intermittent subscript errors in this section:
ReDim ServiceArr(1 To LastRow) '<-- This is only a guess.
j = 1
For Each cell In .Range("B2:B" & LastRow).SpecialCells(xlCellTypeVisible)
Service = Split(cell.Value, ",")
For i = LBound(Service) To UBound(Service)
Service(i) = Trim(Service(i))
If Not Dict.exists(Service(i)) Then
Dict.Add Service(i), Service(i)
ServiceArr(j) = Service(i) '<--Subscript error here if unique elements > LastRow
j = j + 1
End If
Next i
Next cell
The solution is ridiculously easy - get rid of ServiceArr completely. It will always be exactly the same thing as both Dict.Keys and Dict.Values because you're basically keeping a 3rd identical copy of the same data here:
Dict.Add Service(i), Service(i)
ServiceArr(j) = Service(i)
This does almost exactly the same thing as your code, except it gives you a 0 based array instead of a 1 based array:
For Each cell In .Range("B2:B" & LastRow).SpecialCells(xlCellTypeVisible)
Service = Split(cell.Value, ",")
For i = LBound(Service) To UBound(Service)
Service(i) = Trim(Service(i))
If Not Dict.exists(Service(i)) Then
Dict.Add Service(i), Empty
End If
Next i
Next cell
ServiceArr = Dict.Keys
'...
'Adjust this to 0 based.
For i = LBound(ServiceArr) To UBound(ServiceArr)
See #YowE3K's comment for why you get the other error.
Well, just wildly guessing but can you try the following:
Option 1
In stead of:
For i = 1 To UBound(ServiceArr) - 1
For j = i + 1 To UBound(ServiceArr)
Write:
For i = 0 To UBound(ServiceArr) - 1
For j = i + 1 To UBound(ServiceArr)
Option 2
In stead of:
j = 1 ' init array counter
Write:
j = 0 ' init array counter
If nothing works, give information about the line of the error. E.g. once you see the error message, press debug and see on which line is colored in yellow.

VBA Looping/Logic Issue

I am writing a macro in excel for work and I am having trouble. In this scenario there are two sheets, "BU" and "TOPS Information". When the macro is used it is supposed to search every line of "BU" for the value found in "TOPS Information", then go to the next line of "TOPS Information and repeat the process. If it finds a correct match it is supposed to copy a cell and paste it into "TOPS Information".
Here is the code:
Sub QIM()
Dim j As Integer
Dim k As Integer
Dim i As Integer
Dim l As Integer
Dim m As Integer
Dim searchArray(1 To 3) As String
j = 0
k = 1
'WARNING: Temporary Sheet Names
lastRowTOPS = Worksheets("TOPS Information").Cells(Rows.Count, "A").End(xlUp).Row
lastRowBU = Worksheets("BU").Cells(Rows.Count, "A").End(xlUp).Row
'Cycle through BU rows
For j = lastRowTOPS To 1 Step -1
'Cycle through searchArray for each BU row
For k = lastRowBU To 1 Step -1
'//////////////////////////////////////
x = Sheets("BU").Range("B" & k).Value
y = Range("C" & j).Value
If StrComp(x, y) = 1 Then
Sheets("BU").Range("C" & k).Copy
Range("H" & j).PasteSpecial
End If
'//////////////////////////////////////
Next k
Next j
End Sub
This Macro obviously only works if "TOPS Information" is selected at the time. Any and all help would be most appreciated. THANKS!
You sorta answered it yourself. Range refers to the current sheet, but when you're bouncing around then you have to qualify it.
Prefix your ranges with the appropriate sheet like so,
Sub QIM()
Dim j As Integer
Dim k As Integer
Dim i As Integer
Dim l As Integer
Dim m As Integer
Dim searchArray(1 To 3) As String
j = 0
k = 1
'WARNING: Temporary Sheet Names
lastRowTOPS = Worksheets("TOPS Information").Cells(Rows.Count, "A").End(xlUp).Row
lastRowBU = Worksheets("BU").Cells(Rows.Count, "A").End(xlUp).Row
'Cycle through BU rows
For j = lastRowTOPS To 1 Step -1
'Cycle through searchArray for each BU row
For k = lastRowBU To 1 Step -1
'//////////////////////////////////////
x = Sheets("BU").Range("B" & k).Value
y = Sheets("TOPS Information").Range("C" & j).Value
If StrComp(x, y) = 1 Then
Sheets("BU").Range("C" & k).Copy
Sheets("TOPS Information").Range("H" & j).PasteSpecial
End If
'//////////////////////////////////////
Next k
Next j
End Sub
Assuming only want to copy the top most found data in BU to TOPS, you can use below.
Sub QIM()
Dim oWS_TOPS As Worksheet, oWS_BU As Worksheet ' Worksheet objects
Dim oRng_TOPS As Range, oRng_BU As Range ' Range objects
Dim R_TOPS As Long, R_BU As Long
Set oWS_TOPS = ThisWorkbook.Worksheets("TOPS Information") ' <-- Replace this "TOPS Information" to match future changes
Set oWS_BU = ThisWorkbook.Worksheets("BU") ' <-- Replace this "BU" to match future changes
R_TOPS = oWS_TOPS.Cells(Rows.Count, "A").End(xlUp).Row
R_BU = oWS_BU.Cells(Rows.Count, "A").End(xlUp).Row
' Search column B of BU for each cell in column C of TOPS
For Each oRng_TOPS In oWS_TOPS.Columns("C").Cells ' <-- Replace this "C" to match future changes
' Exit if row is more than last A column data
If oRng_TOPS.Row > R_TOPS Then Exit For
For Each oRng_BU In oWS_BU.Columns("B").Cells ' <-- Replace this "B" to match future changes
' Exit if row is more than last A column data
If oRng_BU.Row > R_BU Then Exit For
' Check if Ranges match (## See Update ##)
If InStr(1, oRng_TOPS.Value, oRng_BU.Value, vbTextCompare) > 0 Then
' Copy column C of found row in BU to column H of TOPS, then exit
oWS_BU.Cells(oRng_BU.Row, "C").Copy oWS_TOPS.Cells(oRng_TOPS.Row, "H") ' <-- Replace these "C" and "H" to match future changes
Exit For
End If
Next
Next
Set oWS_TOPS = Nothing
Set oWS_BU = Nothing
End Sub
There are many ways to achieve your goal, and this is one of it.
UPDATE Note on comparing cell values (String):
StrComp(S1,S2[,mode]) only return 3 values {-1, 0, 1} to indicate if S1 is less/equal/greater than S2. If you want an exact match (case sensitive and exact spacing), use If StrComp(S1,S2) = 0 Then.
InStr([i,]S1,S2[,mode]) only returns positive values - it returns the character location of first appearance of S2 in S1. If S2 is not found then it returns zero.
You can also use Trim(sText) to remove leading/ending spaces of sText.
Hope below screenshot says more.

How to delete a row if it contains a string?

I have only one column of data. I need to write a macro that would go through all the values and delete all rows that contain the word "paper".
A B
1 678
2 paper
3 3
4 09
5 89
6 paper
The problem is that the number of rows is not fixed. Sheets may have different number of rows.
Here is another simple macro that will remove all rows with non-numeric values in column A (besides row 1).
Sub DeleteRowsWithStringsInColumnA()
Dim i As Long
With ActiveSheet '<~~ Or whatever sheet you may want to use the code for
For i = .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, 1).Row To 2 Step -1 '<~~ To row 2 keeps the header
If IsNumeric(.Cells(i, 1).Value) = False Then .Cells(i, 1).EntireRow.Delete
Next i
End With
End Sub
If you're confident that the rows in question would always contain "paper" specifically and never any other string, you should match based on the value paper rather than it being a string. This is because, particularly in Excel, sometimes you may have numbers stored as strings without realizing it--and you don't want to delete those rows.
Sub DeleteRowsWithPaper()
Dim a As Integer
a = 1
Do While Cells(a, 1) <> ""
If Cells(a, 1) = "paper" Then
Rows(a).Delete Shift:=xlUp
'Row counter should not be incremented if row was just deleted
Else
'Increment a for next row only if row not deleted
a = a + 1
End If
Loop
End Sub
The following is a flexible macro that allows you to input a string or number to find and delete its respective row. It is able to process 1.04 million rows of simple strings and numbers in 2.7 seconds.
Sub DeleteRows()
Dim Wsht As Worksheet
Dim LRow, Iter As Long
Dim Var As Variant
Var = InputBox("Please specify value to find and delete.")
Set Wsht = ThisWorkbook.ActiveSheet
LRow = Wsht.Cells(Rows.Count, 1).End(xlUp).Row
StartTime = Timer
Application.ScreenUpdating = False
With Wsht
For Iter = LRow To 1 Step -1
If InStr(.Cells(Iter, 1), Var) > 0 Then
.Cells(Iter, 1).EntireRow.Delete
End If
Next Iter
End With
Application.ScreenUpdating = True
Debug.Print Timer - StartTime
End Sub

Return text when looking up data

I have a spreadsheet which looks like this:
Name Task Date
Mike Go to the beach 10/1/13
Mike Go Shopping 10/2/13
Mike Go to work 10/3/13
Bill Go Hiking 10/1/13
Bill Go to work 10/3/13
I am trying to build another tab to the spreadsheet which will look at the data tab and return the matching text value when the rows and the columns match.
I'm trying to use a formula create a type of pivot table.
The results should look like this:
Name 10/1/13 10/2/13 10/3/13
Mike Go to the beach Go shopping Go to work
Bill Go Hiking *Blank* Go to work
I tried to post images but couldn't since this is my first post.
I hope you can understand what I am asking.
I am no expert in Pivot Tables, I have done it the dumb way - but works. Assumptions:
1) Source Data always on "Sheet1" with those 3 column headers
2) The "Sheet2" will be used to store sorted data
Sub SO_19105503()
Const NameCol As Long = 1
Const TaskCol As Long = 2
Const DateCol As Long = 3
Dim oShSrc As Worksheet, oShTgt As Worksheet, R As Long, C As Long
Dim aNames As Variant, aDates As Variant
Dim lNames As Long, lDates As Long
Dim oRng As Range, oArea As Range
Set oShSrc = ThisWorkbook.Worksheets("Sheet1") ' Source worksheet with original data
oShSrc.Copy Before:=oShSrc
Set oShSrc = ThisWorkbook.Worksheets("Sheet1 (2)") ' Copy of Source worksheet
Set oShTgt = ThisWorkbook.Worksheets("Sheet2") ' Target worksheet to store sorted data
oShSrc.AutoFilterMode = False
' Get unique names (sorted) in column A
aNames = Array()
lNames = 0
R = 1
oShSrc.UsedRange.Sort Key1:=oShSrc.Cells(R, NameCol), Header:=xlYes
Do
R = R + 1
If Not IsEmpty(oShSrc.Cells(R, NameCol)) And oShSrc.Cells(R, NameCol).Value <> oShSrc.Cells(R - 1, NameCol).Value Then
ReDim Preserve aNames(lNames)
aNames(lNames) = oShSrc.Cells(R, NameCol).Value
lNames = lNames + 1
End If
Loop Until IsEmpty(oShSrc.Cells(R, NameCol))
' Get unique dates (sorted) in column C
aDates = Array()
lDates = 0
R = 1
oShSrc.UsedRange.Sort Key1:=oShSrc.Cells(R, DateCol), Header:=xlYes
Do
R = R + 1
If Not IsEmpty(oShSrc.Cells(R, DateCol)) And oShSrc.Cells(R, DateCol).Value <> oShSrc.Cells(R - 1, DateCol).Value Then
ReDim Preserve aDates(lDates)
aDates(lDates) = oShSrc.Cells(R, DateCol).Value
lDates = lDates + 1
End If
Loop Until IsEmpty(oShSrc.Cells(R, DateCol))
' Prepare and put data to Target sheet
oShTgt.Range("A1").Value = oShSrc.Range("A1").Value ' Name
' Insert Dates (start from column B on Row 1)
For C = 0 To lDates - 1
oShTgt.Cells(1, C + 2).Value = aDates(C)
Next
' Insert Names (start from Row 2 on Column A)
For R = 0 To lNames - 1
oShTgt.Cells(R + 2, 1).Value = aNames(R)
Next
' Reprocess the source data with Autofilter
For R = 0 To lNames - 1
oShSrc.AutoFilterMode = False ' Remove AutoFilter before apply
' Apply AutoFilter with Criteria of R'th entry in array aNames
oShSrc.UsedRange.AutoFilter Field:=1, Criteria1:="=" & aNames(R)
' Go through Ranges in each Area
For Each oArea In oShSrc.Cells.SpecialCells(xlCellTypeVisible).Areas
For Each oRng In oArea.Rows
' Stop checking if row is more than used
If oRng.Row > oShSrc.UsedRange.Rows.count Then
Exit For
End If
' Check only if the row is below the header
If oRng.Row > 1 Then
For C = 0 To lDates - 1
' Find the matching date and put the "Task" value
If oShSrc.Cells(oRng.Row, DateCol).Value = aDates(C) Then
oShTgt.Cells(R + 2, C + 2).Value = oShSrc.Cells(oRng.Row, TaskCol).Value
Exit For
End If
Next C
End If
Next oRng
Next oArea
Next R
Application.DisplayAlerts = False
oShSrc.Delete ' Delete the temporary data source sheet
Application.DisplayAlerts = True
Set oShSrc = Nothing
Set oShTgt = Nothing
End Sub
Screenshots - Source Data/Result:

Split Rows on excel based on / in a field

Assume Column B has data such as Data1/Data2/Data3-1/Data3-7 - all other rows have various data.
I need to take each row that has that Column B (some may not) and create 1 row for each individual value, with every other piece of data in the row copied for all of them.
Data may have symbols, dashes, and other random stuff, but the actual data itself will not have a / in it, only / is used to designate split lines
Any1 know the best way to do this? Excel 07 and OO available.
Is a VBA solution OK?
Sub DuplicateRows()
Dim r As Range
Set r = Cells(Rows.Count, 2).End(xlUp)
Do While r.Row > 1
TestRow r
Set r = r.Offset(-1, 0)
Loop
TestRow r
End Sub
Sub TestRow(r As Range)
Dim i As Long, n As Long
Dim a() As String
i = InStr(r, "/")
If i > 0 Then
n = Len(r) - Len(Replace(r, "/", ""))
r.EntireRow.Copy
r.Offset(1, 0).Resize(n).EntireRow.Insert Shift:=xlDown
a = Split(r, "/")
For i = 0 To n
r.Offset(i, 0) = a(i)
Next
End If
Application.CutCopyMode = False
End Sub

Resources