New user here who is also very new to Excel VB.
At the moment, I have a macro which does what you see here.
Essentially, I have 2 columns which can sometimes have cells which contain vertically stacked lines of data in each cell. Each of those lines is split out and put into newly inserted rows below (one line of data in the cell per row).
The problem I am having now, is that while the new rows now contain data in the two columns which had to be split (34 and 35), the remaining cells are empty. I am having trouble bringing the remaining 38 columns down into the newly-created rows. You can see what I mean in the image I posted. Two new rows were created and I need to fill them with the content of row 1 (fill in to the shaded area).
Here is my code right now. The part that is commented out is me trying to fill the empty space. The un-commented code does what you see in the image.
Sub main()
Dim iRow As Long, nRows As Long, nData As Long
Dim IDVariables As Range
Dim arr As Variant
With Worksheets("UI").Columns("AH")
nRows = .Cells(.Rows.Count, 1).End(xlUp).Row
For iRow = nRows To 2 Step -1
With .Cells(iRow)
arr = Split(.Value, vbLf)
nData = UBound(arr) + 1
If nData > 1 Then
.EntireRow.Offset(1).Resize(nData - 1).Insert
.Resize(nData).Value = Application.Transpose(arr)
.Offset(, 1).Resize(nData).Value = Application.Transpose(Split(.Offset(, 1).Value, vbLf))
'Set IDVariables = Range("A" & iRow & ":AG" & iRow)
'IDVariables.Select
'Selection.Copy
'Range("A" & (iRow + 1) & ":A" & (iRow + nData -1)).Select
'Selection.Paste
End If
End With
Next iRow
End With
End Sub
Any help would be very much appreciated.
Thanks!
Tested and working fine....
Option Explicit
Sub ReCode()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim LR As Long, i As Long, arr
LR = ws.Range("AH" & ws.Rows.Count).End(xlUp).Row
For i = LR To 2 Step -1
If InStr(ws.Range("AH" & i), vbLf) Then
ws.Range("A" & i + 1).EntireRow.Insert xlUp
ws.Range("A" & i).EntireRow.Copy ws.Range("A" & i + 1)
arr = Split(ws.Range("AH" & i), vbLf)
ws.Range("AH" & i) = arr(0)
ws.Range("AH" & i + 1) = arr(1)
arr = ""
End If
Next i
End Sub
I'm late doing this but I figured it out. I'll post my solution for anyone who has a similar problem.
Sub main()
Dim iRow As Long, nRows As Long, nData As Long
Dim arr As Variant
Dim IDVariables, Comments, AllocationCheck As Range
Application.ScreenUpdating = False
With Worksheets("PRM2_Computer").Columns("AH")
nRows = .Cells(.Rows.Count, 1).End(xlUp).Row
For iRow = nRows To 2 Step -1
With .Cells(iRow)
arr = Split(.Value, vbLf)
nData = UBound(arr) + 1
If nData = 1 Then
Range("AI" & iRow) = 1
Range("AK" & iRow) = "Single Industry"
End If
If nData > 1 Then
.EntireRow.Offset(1).Resize(nData - 1).Insert
.Resize(nData).Value = Application.Transpose(arr)
.Offset(, 1).Resize(nData).Value = Application.Transpose(Split(.Offset(, 1).Value, vbLf))
.Offset(, 2).Resize(nData).Value = Application.Transpose(Split(.Offset(, 2).Value, vbLf))
Set Comments = Range("AL" & iRow & ":AM" & iRow)
Comments.Copy Range("AL" & (iRow + 1) & ":AL" & (iRow + nData - 1))
Set AllocationCheck = Range("AK" & (iRow) & ":AK" & (iRow + nData - 1))
AllocationCheck.Value = Application.Sum(Range("AI" & iRow & ":AI" & (iRow + nData - 1)))
Set IDVariables = Range("A" & iRow & ":AG" & iRow)
IDVariables.Copy Range("A" & (iRow + 1) & ":A" & (iRow + nData - 1))
End If
End With
Next iRow
End With
End Sub
Related
I have written a piece of code that does reconciliation:
The first part checks between columns.
Works absolutely fine on upto 100k Rows, then simply freezes on anything bigger. Is the an optimal way to write this? Should I be using a scripting dictionary for the reconciliation too? Ive been off VBA for a while now and I am pretty rusty! Thanks for reading and helping.
Sub AutoRecon()
Worksheets("Main_Recon").Select
Dim i As Long, _
LRa As Long, _
LRb As Long, _
rowx As Long
LRa = Range("A" & Rows.Count).End(xlUp).Row
LRb = Range("G" & Rows.Count).End(xlUp).Row
rowx = 2
Application.ScreenUpdating = False
For i = 2 To LRa
If Range("A" & i).Errors.Item(xlNumberAsText).Value = True Then
Range("A" & i).Value = "N" & Range("A" & i).Value
rowx = rowx + 1
End If
Next i
rowx = 2
For i = 2 To LRb
If Range("G" & i).Errors.Item(xlNumberAsText).Value = True Then
Range("G" & i).Value = "N" & Range("G" & i).Value
rowx = rowx + 1
End If
Next i
rowx = 2
For i = 2 To LRa
If IsError(Application.Match(Range("A" & i).Value, Range("G2:G" & LRb), 0)) Then
Range("O" & rowx).Value = Range("A" & i).Value
rowx = rowx + 1
End If
Next i
rowx = 2
For i = 2 To LRb
If IsError(Application.Match(Range("G" & i).Value, Range("A2:A" & LRa), 0)) Then
Range("S" & rowx).Value = Range("G" & i).Value
rowx = rowx + 1
End If
Next i
Application.ScreenUpdating = True
End Sub
This takes too long.
The issue is that you run the loop 4 times, but you can combine 2 loops.
You can gain some speed in the process using arrays to read/write. Every read/write action to a cell needs a lot of time. So the idea is to read all data cells into an array DataA at once (only 1 read action) then process the data in the array and then write it back to the cells at once (only 1 write action). So if you have 100 rows you save 99 read/write actions.
So you would end up with something like below. Note this is untested, so backup before running this.
Option Explicit
Public Sub AutoRecon()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Main_Recon")
Application.ScreenUpdating = False
'find last rows of columns
Dim LastRowA As Long
LastRowA = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim LastRowG As Long
LastRowG = ws.Cells(ws.Rows.Count, "G").End(xlUp).Row
'read data into array
Dim DataA() As Variant 'read data from column A into array
DataA = ws.Range("A1", "A" & LastRowA).Value
Dim DataG() As Variant 'read data from column G into array
DataG = ws.Range("G1", "G" & LastRowG).Value
Dim iRow As Long
For iRow = 2 To Application.Max(LastRowA, LastRowG) 'combine loop to the max of both columns
If iRow <= LastRowA Then 'run only until max of column A
If ws.Cells(iRow, "A").Errors.Item(xlNumberAsText).Value = True Then
DataA(iRow, 1) = "N" & DataA(iRow, 1)
End If
End If
If iRow <= LastRowG Then 'run only until max of column G
If ws.Cells(iRow, "G").Errors.Item(xlNumberAsText).Value = True Then
DataG(iRow, 1) = "N" & DataG(iRow, 1)
End If
End If
Next iRow
'write array back to sheet
ws.Range("A1", "A" & LastRowA).Value = DataA
ws.Range("G1", "G" & LastRowG).Value = DataG
'read data into array
Dim DataO() As Variant 'read data from column O into array (max size = column A)
DataO = ws.Range("O1", "O" & LastRowA).Value
Dim DataS() As Variant 'read data from column G into array (max size = column G)
DataS = ws.Range("S1", "S" & LastRowG).Value
Dim oRow As Long, sRow As Long
oRow = 2 'output row start
sRow = 2
For iRow = 2 To Application.Max(LastRowA, LastRowG) 'combine loop to the max of both columns
If iRow <= LastRowA Then
If IsError(Application.Match(DataA(iRow, 1), DataG, 0)) Then
DataO(oRow, 1) = DataA(iRow, 1)
oRow = oRow + 1
End If
End If
If iRow <= LastRowG Then
If IsError(Application.Match(DataG(iRow, 1), DataA, 0)) Then
DataS(sRow, 1) = DataG(iRow, 1)
sRow = sRow + 1
End If
End If
Next iRow
'write array back to sheet
ws.Range("O1", "O" & LastRowA).Value = DataO
ws.Range("S1", "S" & LastRowG).Value = DataS
Application.ScreenUpdating = True
End Sub
I have two columns J and L.
If the value of J column matches with the corresponding value of L column, both the cells should be highlighted in red.
I am new to this Excel. I am not able to develop this macro.
I tried the below code but it is highlighting J, K and L column if it matches I want only the J and K column to be highlighted and also this macro should start checking from J11 and L11
Sub test()
Dim LastRow As Long, i As Long
Dim arr As Variant
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "J").End(xlUp).Row
arr = .Range("J2" & ":L" & LastRow)
For i = LBound(arr) To UBound(arr)
If arr(i, 1) = arr(i, 3) Then
.Range("J" & i + 1 & ":L" & i + 1).Interior.Color = vbRed
End If
Next i
End With
End Sub
check if is this what u want
Sub test()
Dim LastRow As Long, i As Long
Dim arr As Variant
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "J").End(xlUp).Row
arr = .Range("J11" & ":L" & LastRow)
For i = LBound(arr) To UBound(arr)
If arr(i, 1) = arr(i, 3) Then
.Range("J" & i + 10 & ":J" & i + 10).Interior.Color = vbRed
.Range("L" & i + 10 & ":L" & i + 10).Interior.Color = vbRed
End If
Next i
End With
End Sub
it starts checking from line 11
I think this is the desired output:
Sub test()
Dim LastRow As Long, i As Long
Dim arr As Variant
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "J").End(xlUp).Row
arr = .Range("J2" & ":L" & LastRow)
For i = LBound(arr) To UBound(arr)
If arr(i, 1) = arr(i, 3) Then
.Range("J" & i + 1).Interior.Color = vbRed
.Range("L" & i + 1).Interior.Color = vbRed
End If
Next i
End With
End Sub
Just take them separately.
Select the range with data
Home - Styles - Conditional Formatting
New Rule - Use a formula to determine which cells to format
Format values where this formula is true:
=$J1=$L1
Format - Fill - select your color
Change Applies to (the area where the formatting will apply)
Rule:
Results:
I have data for the year 2019 to 2021 and from 2016 to 2018. I want to combine the data and the KeyNumbers to follow, i was thinking it is best via VBA. But i am clueless on how to do it, so far i move the data from one sheet to this one, and here i have the data collected. But the years is seperated. I need it to be as shown from row R to T. This would be a big help for me, because i have 65 of these sheets. So a simple VBA would be so much help!
Thanks in advance
I tried to write VBA. It is getting there but mixing it up as result
Sub x()
Dim lngDataColumns As Long
Dim lngDataRows As Long
lngDataColumns = 2
lngDataRows = 20
For t = 1 To lngDataRows
Range("n2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("g24:h24").Offset(t).Value)
Range("o2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("i24:j24").Offset(t).Value)
Next t
End Sub
Sub y()
Dim lngDataColumns As Long
Dim lngDataRows As Long
lngDataColumns = 3
lngDataRows = 20
Range("p2").Offset(((t - 1) * lngDataColumns) - 1, 0).Resize(lngDataColumns, 1).Value = _
Application.Transpose(Range("h5").Offset(t).Value)
End Sub
You could try:
Option Explicit
Sub test()
Dim LastrowH As Long, Year As Long, i As Long, LastrowR As Long
Dim Amount As Double
Dim Key As String
With ThisWorkbook.Worksheets("Sheet1")
LastrowH = .Cells(.Rows.Count, "H").End(xlUp).Row
For i = 2 To LastrowH
'Check if Key start from DR (we assume that anything start with DR is key we need)
If Left(.Range("H" & i).Value, 2) = "DR" Then 'Remove this line
Key = .Range("H" & i).Value
Amount = .Range("L" & i).Value
Year = .Range("M" & i).Value
LastrowR = .Cells(.Rows.Count, "R").End(xlUp).Row
.Range("R" & LastrowR + 1).Value = Key
.Range("S" & LastrowR + 1).Value = Amount
.Range("T" & LastrowR + 1).Value = Year
If Year = 2018 Then
.Range("R" & LastrowR + 2 & ":R" & LastrowR + 4).Value = Key
.Range("S" & LastrowR + 2 & ":S" & LastrowR + 4).Value = Amount
.Range("T" & LastrowR + 2).Value = Year + 1
.Range("T" & LastrowR + 3).Value = Year + 2
.Range("T" & LastrowR + 4).Value = Year + 3
End If
End If 'Remove this line
Next i
End With
End Sub
if you want to remove the DR ( if statement) remove the lines with 'Remove this line at the end.
I am building on some code, partly cut and paste from other posts. I need to concatenate with a VBA code keeping the format and running through rows to output in last cell in each row. (Can't paste image) so hope description is clear:
In A1:D1 values are RED,BLUE,GREEN
In A2:D2 Values are YELLOW,PURPLE,ORANGE
OUTPUT IN E1 should concatenate these values, keeping font colour. Each value should have "ALT ENTR" to give line break.
Next row should be displayed in E2, and so on
'************************************************************************************
Sub test()
Dim rng As Range: Set rng = Application.Range("a1:c1") 'Not yet looping
Dim row As Range
For Each row In rng.Rows
'Debug.Print col.Column
Call concatenate_cells_formats(Cells(1, 4), rng) 'Not yet looping
Next row
End Sub
Sub concatenate_cells_formats(cell As Range, source As Range)
'Anon
Dim c As Range
Dim i As Integer
i = 1
With cell
.Value = vbNullString
.ClearFormats
For Each c In source
.Value = .Value & " " & Trim(c)
Next c
.Value = Trim(.Value)
For Each c In source
With .Characters(Start:=i, Length:=Len(Trim(c))).Font
.Name = c.Font.Name
.FontStyle = c.Font.FontStyle
.Size = c.Font.Size
.Strikethrough = c.Font.Strikethrough
.Superscript = c.Font.Superscript
.Subscript = c.Font.Subscript
.OutlineFont = c.Font.OutlineFont
.Shadow = c.Font.Shadow
.Underline = c.Font.Underline
.ColorIndex = c.Font.ColorIndex
End With
.Characters(Start:=i + Len(c), Length:=1).Font.Size = 1
i = i + Len(Trim(c)) + 1
Next c
End With
End Sub
'*****************************************************************************
Option Explicit
Sub concColour()
Dim i As Long, j As Long, s As Long, l As Long, clr As Long, vals As Variant
With Worksheets("sheet4")
For i = 1 To .Cells(.Rows.Count, "A").End(xlUp).Row
vals = Application.Transpose(Application.Transpose(Intersect(.Range("A:D"), .Rows(i)).Value2))
.Cells(i, "E") = Join(vals, vbLf)
s = 1
For j = LBound(vals) To UBound(vals)
l = Len(vals(j))
clr = .Cells(i, "A").Offset(0, j - 1).Font.Color
With .Cells(i, "E").Characters(Start:=s, Length:=l).Font
.Color = clr
End With
s = s + l + 1
Next j
.Cells(i, "E").Font.Size = 4
Next i
End With
End Sub
enter image description here
I think you require something like this. Change source font and formats as per your requirement.
Sub Adding_T()
Dim lena As Integer
Dim lenc As Integer
Dim lend As Integer
Dim lene As Integer
Dim LastRow As Long
Dim nrow As Long
With Worksheets("Sheet2") 'Change sheet as per your requirement
LastRow = .Cells(.Rows.Count, "A").End(xlUp).row
For nrow = 1 To LastRow
.Range("E" & nrow) = .Range("A" & nrow).Value2 & Chr(13) & Chr(10) & .Range("B" & nrow).Value2 & _
Chr(13) & Chr(10) & .Range("C" & nrow).Value2 & Chr(13) & Chr(10) & .Range("D" & nrow).Value2
lena = Len(.Range("A" & nrow).Value2)
lenc = lena + 2 + Len(.Range("B" & nrow).Value2)
lend = lenc + 2 + Len(.Range("C" & nrow).Value2)
lene = lend + 2 + Len(.Range("D" & nrow).Value2)
For i = 1 To lena
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("A" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
For i = lena + 2 To lenc
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("B" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
For i = lenc + 2 To lend
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("C" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
For i = lend + 2 To lene
.Range("E" & nrow).Characters(Start:=i, Length:=1).Font.Color = _
.Range("D" & nrow).Characters(Start:=i, Length:=1).Font.Color
Next i
Next
End With
End Sub
Snapshot of trial:
EDIT: OP Preferred code does not permit looping through the Range. Amended his Sub Test() to allow looping through the range.
Sub Test2()
Dim ws As Worksheet
Dim LastRow As Long
Set ws = ThisWorkbook.ActiveSheet
Dim rng As Range
Dim row As Range
Dim rw As Long
LastRow = ws.Cells(Rows.Count, "A").End(xlUp).row
rw = 1
For rw = 1 To LastRow
Set rng = ws.Range("A" & rw & ":C" & rw)
Call concatenate_cells_formats(Cells(rw, 4), rng)
Next
End Sub
Results are as per snapshot appended here.
This is a follow on from How do I get all the different unique combinations of 3 columns using VBA in Excel?
It almost what i need, however, my requirements is that it sums the third column which will contain figures instead of yes/no
Sub sample()
Dim ws As Worksheet
Dim lRow As Long, i As Long, j As Long
Dim col As New Collection
Dim Itm
Dim cField As String
Const deLim As String = "#"
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = 2 To lRow
cField = .Range("A" & i).Value & deLim & _
.Range("B" & i).Value & deLim & _
.Range("C" & i).Value
On Error Resume Next
col.Add cField, CStr(cField)
On Error GoTo 0
Next i
i = 2
.Range("A1:C1").Copy .Range("F1")
.Range("I1").Value = "Count"
For Each Itm In col
.Range("F" & i).Value = Split(Itm, deLim)(0)
.Range("G" & i).Value = Split(Itm, deLim)(1)
.Range("H" & i).Value = Split(Itm, deLim)(2)
For j = 2 To lRow
cField = .Range("A" & j).Value & deLim & _
.Range("B" & j).Value & deLim & _
.Range("C" & j).Value
If Itm = cField Then nCount = nCount + 1
Next
.Range("I" & i).Value = nCount
i = i + 1
nCount = 0
Next Itm
End With
End Sub
This code was originally added by
Siddharth Rout
try this (follows comments)
Option Explicit
Sub Main()
Dim i As Long
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
For i = 4 To Range("A" & Rows.Count).End(xlUp).Row '<-- change 4 and "A" to your data actual upleftmost cell row and column
dict(cells(i, 1).Value & "|" & cells(i, 2).Value) = dict(cells(i, 1).Value & "|" & cells(i, 2).Value) + cells(i, 3).Value '<--| change 3 to your actual "column to sum up" index
Next
With Range("G3").Resize(dict.Count) '<-- change "G3" to your actual upleftmost cell to start writing output data from
.Value = Application.Transpose(dict.Keys)
.TextToColumns Destination:=.cells, DataType:=xlDelimited, Other:=True, OtherChar:="|"
.Offset(, 2).Resize(dict.Count).Value = Application.Transpose(dict.Items) '<--| change 2 to your actual column offset where to start writing summed values form
End With
End Sub