I am using these codes for text to row purpose but i am not able to convert it after certain Number of rows in Col B. whereas it is working fine for col c and d. one more thing if i am removing the on error resume next then i am getting subscript out of range error. please help me on these errors.
Expected Output for given input:
Code:
Sub Main()
On Error Resume Next
Columns("B:B").NumberFormat = "#"
Dim i As Long, c As Long, r As Range, v As Variant
For i = 1 To Range("B" & Rows.Count).End(xlUp).Row
v = Split(Range("B" & i), ",")
c = c + UBound(v) + 1
Next i
For i = 2 To c
Set r = Range("B" & i)
Dim arr As Variant
arr = Split(r, ",")
Dim j As Long
r = arr(0)
For j = 1 To UBound(arr)
Rows(r.Row + j & ":" & r.Row + j).Insert shift:=xlDown
r.Offset(j, 0) = arr(j)
r.Offset(j, -1) = r.Offset(0, -1)
r.Offset(j, 1) = r.Offset(0, 1)
Next j
Next i
Columns("C:C").NumberFormat = "#"
For i = 1 To Range("C" & Rows.Count).End(xlUp).Row
v = Split(Range("C" & i), ",")
c = c + UBound(v) + 1
Next i
For i = 2 To c
Set r = Range("C" & i)
arr = Split(r, ",")
r = arr(0)
For j = 1 To UBound(arr)
r.Offset(j, 0) = arr(j)
r.Offset(j, 1) = r.Offset(0, 1)
Next j
Next i
Columns("D:D").NumberFormat = "#"
For i = 1 To Range("D" & Rows.Count).End(xlUp).Row
v = Split(Range("D" & i), ",")
c = c + UBound(v) + 1
Next i
For i = 2 To c
Set r = Range("D" & i)
arr = Split(r, ",")
r = arr(0)
For j = 1 To UBound(arr)
r.Offset(j, 0) = arr(j)
r.Offset(j, 1) = r.Offset(0, 1)
Next j
Next i
Columns("E:E").NumberFormat = "#"
For i = 1 To Range("E" & Rows.Count).End(xlUp).Row
v = Split(Range("E" & i), ",")
c = c + UBound(v) + 1
Next i
For i = 2 To c
Set r = Range("E" & i)
arr = Split(r, ",")
r = arr(0)
For j = 1 To UBound(arr)
r.Offset(j, 0) = arr(j)
r.Offset(j, 1) = r.Offset(0, 1)
Next j
Next i
End Sub
Here is a code that works.
Before:
Inv Hours Bill am Loc
1 10,12 1,2 10,24 BANG,KOL
2 1,2,3 1,2,3 1,4,9 A,B,C
After:
Inv Hours Bill am Loc
1 10 1 10 BANG
1 12 2 24 KOL
2 1 1 1 A
2 2 2 4 B
2 3 3 9 C
Option Explicit
Sub Main()
Columns("B:B").NumberFormat = "#"
Dim i As Long, c As Long, r As Range, v As Variant
For i = 1 To Range("B" & Rows.Count).End(xlUp).Row
v = Split(Range("B" & i), ",")
c = c + UBound(v) + 1
Next i
For i = 2 To c
Set r = Range("B" & i)
Dim arr As Variant
arr = Split(r, ",")
Dim j As Long
r = arr(0)
For j = 1 To UBound(arr)
Rows(r.Row + j & ":" & r.Row + j).Insert shift:=xlDown
r.Offset(j, 0) = arr(j)
r.Offset(j, -1) = r.Offset(0, -1)
r.Offset(j, 1) = r.Offset(0, 1)
Next j
Next i
Columns("C:C").NumberFormat = "#"
For i = 1 To Range("C" & Rows.Count).End(xlUp).Row
v = Split(Range("C" & i), ",")
'c = c + UBound(v) + 1
Next i
For i = 2 To c
Set r = Range("C" & i)
arr = Split(r, ",")
r = arr(0)
For j = 1 To UBound(arr)
r.Offset(j, 0) = arr(j)
r.Offset(j, 1) = r.Offset(0, 1)
Next j
Next i
Columns("D:D").NumberFormat = "#"
For i = 1 To Range("D" & Rows.Count).End(xlUp).Row
v = Split(Range("D" & i), ",")
'c = c + UBound(v) + 1
Next i
For i = 2 To c
Set r = Range("D" & i)
arr = Split(r, ",")
r = arr(0)
For j = 1 To UBound(arr)
r.Offset(j, 0) = arr(j)
r.Offset(j, 1) = r.Offset(0, 1)
Next j
Next i
Columns("E:E").NumberFormat = "#"
For i = 1 To Range("E" & Rows.Count).End(xlUp).Row
v = Split(Range("E" & i), ",")
'c = c + UBound(v) + 1
Next i
For i = 2 To c
Set r = Range("E" & i)
arr = Split(r, ",")
r = arr(0)
For j = 1 To UBound(arr)
r.Offset(j, 0) = arr(j)
r.Offset(j, 1) = r.Offset(0, 1)
Next j
Next i
End Sub
So here is a code that works (reposted here as I guess you will close your other question):
Option Explicit
Sub SplitByRows()
Dim Col As Long, LastRow As Long, ColParts() As String
Dim i, a, k As Long
Dim StringNo As String
LastRow = Cells(Rows.Count, "B").End(xlUp).Row
For i = 2 To LastRow
k = CountChrInString(Cells(i, 2).Value, ",")
StringNo = Cells(i, 1).Value
For a = 1 To k
Cells(i, 1).Value = Cells(i, 1).Value & "," & StringNo
Next a
Next i
For Col = 1 To 5 'Column A to Column C
ColParts = Split(Join(Application.Transpose(Range(Cells(2, Col), Cells(LastRow, Col))), ","), ",")
With Cells(2, Col).Resize(UBound(ColParts) + 1)
.NumberFormat = "_(* #,##0.00_);_(* (#,##0.00);_(* ""-""??_);_(#_)"
.Value = Application.Transpose(ColParts)
End With
Next
End Sub
Public Function CountChrInString(Expression As String, Character As String) As Long
Dim iResult As Long
Dim sParts() As String
sParts = Split(Expression, Character)
iResult = UBound(sParts, 1)
If (iResult = -1) Then
iResult = 0
End If
CountChrInString = iResult
End Function
All I did was adding some "," to the first column as well at the beginning of your code.
For this I needed to count the amount of "," in the cell of the second column.
This was done with the function from this page: How to find Number of Occurences of Slash from a strings
After that your code just did the rest ;)
Related
I have three columns, one of them having all the staff list IDs, the second is having Front-Line staff IDs, The third is having the Back-office staff IDs, sometimes we change the task to some of them, to work in the different field, So His Staff ID has to disappear from Front-Line col and appear in Back-Office col instead. and Vice-Versa, and this will be done by selecting some of Column A staff, then it will loop through Col B and remove selection value(If found), then add these selected cells to Col B.
The same when we normalize, we select some staff from Col A, It should remove the staff IDs from Col B and add it to col C
All Staff | Front-line | Back-Office
15348 | 15348 | 15344
15347 | 15347 | 15345
15345 |
15344 |
What I've achieved so far.
Excuse me if my codes looks a little bit complex, that's the only way I know.
Dedicate Button (Dedicating 1st Col staffs to work as Back-office)
Dim found As Boolean
Dim i, j, mycount, dedlist As Integer
Dim firstempty As Long
With Sheets("StaffList")
firstempty = .Range("H" & .Rows.Count).End(xlUp).Row + 1
dedlist = .Range("L" & .Rows.Count).End(xlUp).Row
End With
mycount = firstempty - 1
found = False
Selection.Copy
With Sheets("StaffList")
firstempty = .Range("H" & .Rows.Count).End(xlUp).Row + 1
Cells(firstempty, 8).Select
Cells(firstempty, 8).PasteSpecial Paste:=xlPasteValues
End With
With Sheets("StaffList")
firstempty = .Range("H" & .Rows.Count).End(xlUp).Row + 1
dedlist = .Range("L" & .Rows.Count).End(xlUp).Row
End With
mycount = firstempty - 1
For i = 2 To mycount
For j = 2 To dedlist
With Sheets("StaffList")
If .Range("H" & i).Value = .Range("L" & j).Value Then
found = True
End If
End With
Next j
If found = False Then
dedlist = dedlist + 1
With Sheets("StaffList")
.Range("L" & dedlist).Value = .Range("H" & i).Value
End With
End If
found = False
Next i
' ActiveSheet.Range("$H$1:$H$500").RemoveDuplicates Columns:=1, Header:=xlYes
Range("A1").Select
Normalize Button (Normalizing 2nd Col staffs to get back working as Front-Line)
Dim CompareRange As Variant, x As Variant, y As Variant
Dim rng As Range
Dim found As Boolean
Dim i, j, mycount, dedlist As Integer
Dim firstempty As Long
With Sheets("StaffList")
firstempty = .Range("M" & .Rows.Count).End(xlUp).Row + 1
dedlist = .Range("H" & .Rows.Count).End(xlUp).Row
End With
mycount = firstempty - 1
found = False
Selection.Copy
With Sheets("StaffList")
firstempty = .Range("M" & .Rows.Count).End(xlUp).Row + 1
Cells(firstempty, 13).Select
Cells(firstempty, 13).PasteSpecial Paste:=xlPasteValues
End With
With Sheets("StaffList")
firstempty = .Range("M" & .Rows.Count).End(xlUp).Row + 1
dedlist = .Range("H" & .Rows.Count).End(xlUp).Row
End With
mycount = firstempty - 1
For i = 2 To mycount
For j = 2 To dedlist
With Sheets("StaffList")
If .Range("M" & i).Value = .Range("L" & j).Value Then
.Range("H" & j).Value = ""
End If
End With
Next j
Next i
Range("A1").Select
This is the VBA implementation of the suggestion in comment:
Option Explicit
Public Sub UpdateStaffTasks()
Const FRNT = "Front-line", BACK = "Back-Office"
Dim selRow As Variant, lrSelRow As Long, ws As Worksheet, i As Long, j As Long
Dim usdRng As Variant, lrUsdRng As Long, red As Long, blu As Long
If Selection.Cells.Count = 1 And Selection.Row = 1 Then Exit Sub
Set ws = Selection.Parent
selRow = GetSelRows(Selection): lrSelRow = UBound(selRow): red = RGB(256, 222, 222)
usdRng = ws.UsedRange: lrUsdRng = UBound(usdRng): blu = RGB(222, 222, 256)
For i = 0 To lrSelRow
For j = i + 2 To lrUsdRng
If j = Val(selRow(i)) Then
If Len(usdRng(j, 1)) > 0 And Len(usdRng(j, 2)) > 0 Then
usdRng(j, 2) = IIf(usdRng(j, 2) = FRNT, BACK, FRNT)
With ws.Cells(j, 1).Resize(, 2).Interior
.Color = IIf(usdRng(j, 2) = FRNT, red, blu)
End With
Exit For
End If
End If
Next
Next
Selection.Parent.UsedRange = usdRng
End Sub
Public Function GetSelRows(ByRef selectedRange As Range) As Variant
Dim s As Variant, a As Range, r As Range, result As Variant
If selectedRange.Cells.Count > 1 Then
For Each a In selectedRange.Areas
For Each r In a.Rows
If r.Row > 1 And InStr(s, r.Row) = 0 Then s = s & r.Row & " "
Next
Next
GetSelRows = Split(RTrim$(s)): Exit Function
Else
GetSelRows = Array(selectedRange.Row): Exit Function
End If
End Function
Before and After:
I wanna write a macro which copy the 1 cells to another sheet if they contain some value.
Table:
Expectation:
So far I tried this but it copy only last cell from sheet1 to first cell in sheet 2
Sub CopyBasedonSheet1()
Dim i As Integer
Dim j As Integer
Sheet1LastRow = Worksheets("Sheet1").Range("B" & Rows.Count).End(xlUp).Row
Sheet2LastRow = Worksheets("Sheet2").Range("B" & Rows.Count).End(xlUp).Row
For j = 1 To Sheet1LastRow
For i = 1 To Sheet2LastRow
If Worksheets("Sheet1").Cells(j, 2).Value = "a" Then
Worksheets("Sheet2").Cells(i, 1).Value = Worksheets("Sheet1").Cells(j, 1).Value
Else
End If
Next i
Next j
End Sub
You should do it with one loop, because when you have a row from the first sheet, there is only 1 place where you want to copy it, not many:
Sub CopyBasedonSheet1()
Dim i As Integer
Dim j As Integer
Sheet1LastRow = Worksheets("Sheet1").Range("B" & Rows.Count).End(xlUp).Row
i = 1
For j = 1 To Sheet1LastRow
If Worksheets("Sheet1").Cells(j, 2).Value = "a" Then
Worksheets("Sheet2").Cells(i, 1).Value = Worksheets("Sheet1").Cells(j, 1).Value
Worksheets("Sheet2").Cells(i, 2).Value = Worksheets("Sheet1").Cells(j, 2).Value
i = i + 1
End If
Next j
End Sub
Or you may try a different approach altogether which is faster also...
Sub CopyData()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim x, y()
Dim i As Long, j As Long
Set ws1 = Sheets("Sheet1")
Set ws2 = Sheets("Sheet2")
x = ws1.Range("A1").CurrentRegion.Value
ReDim y(1 To Application.CountIf(ws1.Columns(2), "a"), 1 To 2)
j = 1
For i = 1 To UBound(x, 1)
If x(i, 2) = "a" Then
y(j, 1) = x(i, 1)
y(j, 2) = x(i, 2)
j = j + 1
End If
Next i
ws2.Range("A:B").Clear
ws2.Range("A1").Resize(UBound(y, 1), 2).Value = y
End Sub
Sub ddf()
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Dim x As Double
Dim y As Double
Do Until Range("a1").Value = ""
x = InStr(1, Range("a1"), ".")
y = InStr(1, Range("a1"), "?")
lr = Cells(Rows.Count, 1).End(xlUp).Row
If x > y Then
Range("a" & lr + 1).Formula = Left(Range("a1"), y)
Range("a1") = Replace(Range("a1"), Range("a" & lr + 1), "")
ElseIf x = 0 Then
Range("a" & lr + 1).Formula = Left(Range("a1"), y)
Range("a1") = Replace(Range("a1"), Range("a" & lr + 1), "")
ElseIf y = 0 Then
Range("a" & lr + 1).Formula = Left(Range("a1"), x - 1)
Range("a1") = Replace(Range("a1"), Left(Range("a1"), x), "")
Else
Range("a" & lr + 1).Formula = Left(Range("a1"), x - 1)
Range("a1") = Replace(Range("a1"), Left(Range("a1"), x), "")
End If
Loop
Exit Sub
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
In above code i want to loop the steps till range("a1") become blank. Please tell me where need corrections in above code.
Place
x = InStr(1, Sheets("sheet1").Range("a1"), ".")
y = InStr(1, Sheets("sheet1").Range("a1"), "?")
Also right before
Loop
And place both just after the last
End If
I tried to write comparison in Excel macro for my work. Somehow, it is working not in the way I wanted the output. What I want is to compare the two columns and show the differences between them. If empty field on one column, the program should skip a line. Here is my code:
Sub run_compare_main()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Dim last_row As Integer
Dim input_array As Variant
Dim output_aray() As String
Dim a_counter As Integer
Dim b_counter As Integer
last_row = get_last_row("INPUT", "A")
ReDim output_array(1 To (last_row * 2), 1 To 5) '(last_row * 2)
input_array = Range("A7:D7" & (last_row * 2)).Value2
a_counter = 1
b_counter = 1
For i = 1 To (last_row * 2)
If input_array(a_counter, 1) = input_array(b_counter, 3) Then
output_array(i, 1) = input_array(a_counter, 1)
output_array(i, 2) = input_array(a_counter, 2)
output_array(i, 3) = input_array(b_counter, 3)
output_array(i, 4) = input_array(b_counter, 4)
a_counter = a_counter + 1
b_counter = b_counter + 1
ElseIf input_array(a_counter, 1) = input_array(a_counter - 1, 1) Then
output_array(i, 1) = input_array(a_counter, 1)
output_array(i, 2) = input_array(a_counter, 2)
a_counter = a_counter + 1
ElseIf input_array(b_counter, 3) = input_array(b_counter - 1, 3) Then
output_array(i, 3) = input_array(b_counter, 3)
output_array(i, 4) = input_array(b_counter, 4)
b_counter = b_counter + 1
End If
'find smaller value
If input_array(a_counter, 1) < input_array(b_counter, 3) Or input_array(b_counter, 1) = "" Then
output_array(i, 1) = input_array(a_counter, 1)
output_array(i, 2) = input_array(a_counter, 2)
a_counter = a_counter + 1
Else
output_array(i, 3) = input_array(b_counter, 3)
output_array(i, 4) = input_array(b_counter, 2)
b_counter = b_counter + 1
End If
If a_counter = last_row - 5 Or b_counter = last_row - 5 Then
Exit For
End If
Next
Call newtab("OUTPUT")
Range("A7").Resize(last_row, 4).Value = output_array
Sheets("INPUT").Range("A5:D6").Copy
Sheets("OUTPUT").Range("A5").Select
ActiveSheet.Paste
Columns("B:B").ColumnWidth = 80
Columns("D:D").ColumnWidth = 80
Dim LastCol As Long
Dim LastRow As Long
LastCol = ActiveSheet.UsedRange.Columns.Count
LastRow = ActiveSheet.UsedRange.Rows.Count
FilePath = "D:\Try\support.txt"
Open FilePath For Output As #2
CellData = ""
For i = 1 To LastRow
For j = 1 To LastCol
CellData = "The Value at location (" & i & "," & j & ") " & Trim(ActiveCell(i, j).Value)
Write #2, CellData
Next j
Next i
Close #2
MsgBox ("Job Done")
End Sub
Sub newtab(sheetname As String)
Application.DisplayAlerts = False
On Error Resume Next
Sheets(sheetname).Delete
Application.DisplayAlerts = True
Sheets.Add After:=Sheets(Sheets.Count)
Sheets(Sheets.Count).Activate
Sheets(Sheets.Count).Name = sheetname
End Sub
Function get_last_row(ByVal sheetname As String, column As String) As Integer
With Sheets(sheetname)
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
LastRow = .Cells.Find(What:="*", _
After:=.Range(column & "1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
End If
End With
get_last_row = LastRow
End Function
and here my worksample:
Does anyone know how i could expand this code to include 2 more columns of data in its pasting. (columns C and D)
Sub SpecialCopy()
'Assuming A and B columns source columns
Dim i As Long, k As Long
Dim j As Long: j = 1
Dim ArrayLength As Long: ArrayLength = _
Application.WorksheetFunction.Sum(ActiveSheet.Range("B:B"))
ReDim MyArray(1 To ArrayLength) As String
For i = 1 To Cells(Cells.Rows.Count, 1).End(xlUp).Row
k = 1
Do While k <= Range("B" & i).Value
MyArray(j) = Range("A" & i).Value
j = j + 1
k = k + 1
Loop
Next i
For Each MyCell In Range("a1:a" & ArrayLength)
MyCell.Value = MyArray(MyCell.Row())
MyCell.Offset(0, 1).Value = 1
Next MyCell
End Sub
Currently the code separates this:
TREVDAN 2
CENTRAL 3
GAL FAB 1
Into this:
TREVDAN 1
TREVDAN 1
CENTRAL 1
CENTRAL 1
CENTRAL 1
GAL FAB 1
Try this:
Sub SpecialCopy()
'Assuming A and B columns source columns
Dim i As Long, k As Long
Dim j As Long: j = 1
Dim ArrayLength As Long: ArrayLength = _
Application.WorksheetFunction.Sum(ActiveSheet.Range("B:B"))
ReDim MyArray(1 To ArrayLength) As String
ReDim ArrayC(1 To ArrayLength) As String 'new
ReDim ArrayD(1 To ArrayLength) As String 'new
For i = 1 To Cells(Cells.Rows.Count, 1).End(xlUp).Row
k = 1
Do While k <= Range("B" & i).Value
MyArray(j) = Range("A" & i).Value
ArrayC(j) = Range("C" & i).Value 'new
ArrayD(j) = Range("D" & i).Value 'new
j = j + 1
k = k + 1
Loop
Next i
For Each MyCell In Range("a1:a" & ArrayLength)
MyCell.Value = MyArray(MyCell.Row())
MyCell.Offset(0, 1).Value = 1
Next MyCell
For Each MyCell In Range("C1:C" & ArrayLength) 'new
MyCell.Value = ArrayC(MyCell.Row())
MyCell.Offset(0, 1).Value = 1
Next MyCell
For Each MyCell In Range("D1:D" & ArrayLength) 'new
MyCell.Value = ArrayD(MyCell.Row())
MyCell.Offset(0, 1).Value = 1
Next MyCell
End Sub
This is what I landed up doing:
Sub Splitting()
'splitting up rows
'quantity column: AI
'Data columns: AF,AG,AH,AJ
firstrow = Range("AF2:AJ2")
Dim i As Long, k As Long
Dim j As Long: j = 1
'Next line of code is setting array length equal to the quanity column sum
Dim ArrayLength As Long: ArrayLength = _
Application.WorksheetFunction.Sum(ActiveSheet.Range("AI:AI"))
'Redimentioning all data array to have this fixed array length
ReDim First_Array(1 To ArrayLength) As String
ReDim Second_Array(1 To ArrayLength) As String
ReDim Third_Array(1 To ArrayLength) As String
ReDim Fourth_Array(1 To ArrayLength) As String
For i = 1 To Cells(Cells.Rows.Count, 1).End(xlUp).Row
k = 1
Do While k <= Range("AI" & i).Value
First_Array(j) = Range("AF" & i).Value
Second_Array(j) = Range("AG" & i).Value
Third_Array(j) = Range("AH" & i).Value
Fourth_Array(j) = Range("AJ" & i).Value
j = j + 1
k = k + 1
Loop
Next i
'Data Placement
For Each MyCell In Range("AF2:AF" & ArrayLength)
MyCell.Value = First_Array(MyCell.Row())
Next MyCell
For Each MyCell In Range("AG2:AG" & ArrayLength)
MyCell.Value = Second_Array(MyCell.Row())
Next MyCell
For Each MyCell In Range("AH2:AH" & ArrayLength)
MyCell.Value = Third_Array(MyCell.Row())
Next MyCell
For Each MyCell In Range("AJ2:AJ" & ArrayLength)
MyCell.Value = Fourth_Array(MyCell.Row())
Next MyCell
'bring back first row
Range("AF2:AJ2").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Cut
Range("AF3").Select
ActiveSheet.Paste
Range("Af1").Select
Range("AF2:AJ2") = firstrow
'replace quantity column with 1
For Each MyCell In Range("AI2:AI" & ArrayLength + 1)
MyCell.Value = 1
Next MyCell
End sub
Personally I would do it without the arrays...
Sub VBA_Special_Copy_Loop()
Dim lngLastRow As Long, rngSource As Range, iMax As Integer
Dim x As Integer, y As Integer, WF As Object
Set WF = Application.WorksheetFunction
lngLastRow = Range("AF1").Offset(Rows.Count - 1).End(xlUp).Row
Columns("AG").Insert
With Range("AG1").Resize(lngLastRow)
.Formula = "=ROW()"
.Value = .Value
.Cells(1) = "Row"
End With
Set rngSource = Range("AF1").Resize(lngLastRow, 6)
iMax = WF.Max(rngSource.Columns(5))
For x = 2 To iMax
If WF.CountIf(rngSource.Columns(5), x) > 0 Then
rngSource.AutoFilter Field:=5, Criteria1:=x
For y = 2 To x
rngSource.Copy Range("AF1").Offset(lngLastRow)
Range("AF1").Offset(lngLastRow).Resize(, 6).Delete Shift:=xlUp
lngLastRow = Range("AF1").Offset(Rows.Count - 1).End(xlUp).Row
Next y
End If
Next x
rngSource.AutoFilter
Range("AF2").Resize(lngLastRow - 1, 6).Sort Key1:=Range("AG1")
Columns("AG").Delete
End Sub