I'm really new to vba and would appreciate any assistance in the following problem I'm having.
Problem description (in relation to diagram below):
1*) In c, I have managed to separate the return carriages, which leads to 2*) now that each return carriage has it's own row, I need column b and c on either side to be filled down as shown in result 3*)
1*) b c e
y 1,2,3,4 y
z 5,6,7,8 z
2*) b c e
y 1 y
2
3
4
z 5 z
6
7
8
3*) b c e
y 1 y
y 2 y
y 3 y
y 4 y
z 5 z
z 6 z
z 7 z
z 8 z
I have included my original code for everyone to inspect, I am currently stuck as to how I would get to step 3.
Sub InString()
Dim rColumn As Range 'Set this to the column which needs to be worked through
Dim lFirstRow As Long
Dim lLastRow As Long
Dim lRow As Long 'Difference between first and last row
Dim lLFs As Long
Dim rRow As Range 'This will be used to drag the fill down between rows
Set rColumn = Columns("N")
lFirstRow = 2 'Starting may need to be adjusted, if additional columns are added
lLastRow = rColumn.Cells(Rows.Count).End(xlUp).Row
For lRow = lLastRow To lFirstRow Step -1
lLFs = Len(rColumn.Cells(lRow)) - Len(Replace(rColumn.Cells(lRow), vbLf, ""))
If lLFs > 0 Then
rColumn.Cells(lRow + 1).Resize(lLFs).EntireRow.Insert shift:=xlShiftDown 'added EntireRow to before insert, to bring whole row down, instead of previous issue where only rColumn was shifted down.
rColumn.Cells(lRow).Resize(lLFs + 1).Value = Application.Transpose(Split(rColumn.Cells(lRow), vbLf))
End If
Next lRow
End Sub
Thanks,
I just added a loop at the end looking for blanks -
Sub InString()
Dim rColumn As Range 'Set this to the column which needs to be worked through
Dim lFirstRow As Long
Dim lLastRow As Long
Dim lRow As Long 'Difference between first and last row
Dim lLFs As Long
Dim rRow As Range 'This will be used to drag the fill down between rows
Dim strVal As String
Set rColumn = Columns("N")
lFirstRow = 2 'Starting may need to be adjusted, if additional columns are added
lLastRow = rColumn.Cells(Rows.Count).End(xlUp).row
For lRow = lLastRow To lFirstRow Step -1
lLFs = Len(rColumn.Cells(lRow)) - Len(Replace(rColumn.Cells(lRow), vbLf, ""))
If lLFs > 0 Then
rColumn.Cells(lRow + 1).Resize(lLFs).EntireRow.Insert shift:=xlShiftDown 'added EntireRow to before insert, to bring whole row down, instead of previous issue where only rColumn was shifted down.
rColumn.Cells(lRow).Resize(lLFs + 1).Value = Application.Transpose(Split(rColumn.Cells(lRow), vbLf))
End If
Next lRow
lLastRow = rColumn.Cells(Rows.Count).End(xlUp).row
Dim rColNum As Integer
rColNum = rColumn.Column
For i = 2 To lLastRow
If Cells(i, rColNum - 1) = "" Then
Cells(i, rColNum - 1) = Cells(i - 1, rColNum - 1)
Cells(i, rColNum + 1) = Cells(i - 1, rColNum + 1)
End If
Next
End Sub
Basically this part -
For i = 2 To lLastRow
If Cells(i, rColNum - 1) = "" Then
Cells(i, rColNum - 1) = Cells(i - 1, rColNum - 1)
Cells(i, rColNum + 1) = Cells(i - 1, rColNum + 1)
End If
Next
Says, look at each row in the column we just split and see if the cell to the left is blank. If it is, make it the same as the one above it AND make the cell to the right the same as the one above it.
To expand, you might then say
if Cells(i, rColNum - 1) = "" Then
Cells(i, rColNum - 1) = Cells(i - 1, rColNum - 1)
Cells(i, rColNum + 1) = Cells(i - 1, rColNum + 1)
Cells(i, rColNum - 2) = Cells(i - 1, rColNum - 2)
Cells(i, rColNum + 2) = Cells(i - 1, rColNum + 2)
End If
If you wanted to cover the adjacent two columns on either side of rcolumn.
Assuming your input data is in columns B, D and E (as your diagram suggests) then this does the job I think:
Sub OrderData()
Dim inputData As Range, temp() As Variant, splitData As Variant, i As Integer, j As Integer, rw As Long
Set inputData = Range("B1:E2") //Update to reflect your data
temp = inputData.Value
inputData.ClearContents
rw = 1
For i = 1 To UBound(temp)
splitData = Split(temp(i, 2), ",")
For j = 0 To UBound(splitData)
Cells(rw, 2) = temp(i, 1)
Cells(rw, 3) = splitData(j)
Cells(rw, 5) = temp(i, 4)
rw = rw + 1
Next j
Next i
End Sub
Related
I found a VBA code online which does the hardest part of splitting absences data from ranges to separate line for each day. But one thing I cannot figure out how to do it is how to assign a number to each day that was requested. Could anyone help me? For better understanding see screenshot. Greatly appreciated!
Yellow and Green coloured lines separates events. Orange is the thing I am trying to accomplish. Absences
Sub One_Day_Per_Row()
Dim a, b
Dim rws As Long, sr As Long, i As Long, j As Long, k As Long, r As Long
a = Range("A2", Range("A" & Rows.Count).End(xlUp)).Resize(, 6).Value
rws = UBound(a, 1)
For r = 1 To rws
a(r, 6) = a(r, 5) - a(r, 4) + 1
k = k + a(r, 6)
Next r
If k < Rows.Count Then
ReDim b(1 To k, 1 To 4)
sr = 1
For r = 1 To rws
For i = 0 To a(r, 6) - 1
For j = 1 To 3
b(sr + i, j) = a(r, j)
Next j
b(sr + i, 4) = a(r, 4) + i
Next i
sr = sr + a(r, 6)
Next r
Range("G2").Resize(k, 4).Value = b
Range("G1:J1").Value = Array("emp number", "emp name", "absence code", "date")
Else
MsgBox "Too many rows"
End If
End Sub
Something like this should work:
Sub Tester()
Dim data, rw As Long, ws As Worksheet, dStart, dEnd, d, n As Long
Dim cOut As Range
Set ws = ActiveSheet 'or whatever
'read the data
data = ws.Range("A2:E" & ws.Cells(Rows.Count, "A").End(xlUp).Row).Value
Set cOut = ws.Range("G2") 'cell to begin output
For rw = 1 To UBound(data, 1)
dStart = data(rw, 4) 'start date
dEnd = data(rw, 5) 'end date
n = 1 'reset counter
For d = dStart To dEnd 'loop date range
cOut.Resize(1, 3).Value = Array(data(rw, 1), data(rw, 2), data(rw, 3))
cOut.Offset(0, 3).Value = d
cOut.Offset(0, 4).Value = n
n = n + 1
Set cOut = cOut.Offset(1, 0) 'next output row
Next d
Next rw
End Sub
I am trying to add a line of cells in a sheet to a multicolumn listbox in a userform. The number of columns in the sheet also varies. I keep getting the error 'Type mismatch.' Stepping through my code I found that it occurs at the first .AddItem line. I found out that you cannot add multiple items with .AddItem. Is there another method to do this? I'm very new to vba. Thanks for your help!
Private Sub GenerateButton_Click()
Dim i As Long, counter As Long, counter_RA As Long, x As Integer
Dim LastColRA As Long, LastColCP As Long
LastColRA = Sheet1.Cells(1, Columns.Count).End(xlToLeft).Column
LastColCP = Sheet2.Cells(1, Columns.Count).End(xlToLeft).Column
'Check to make sure that enough items were selected
For x = 0 To ListBox2.ListCount - 1
If ListBox2.Selected(x) Then
counter_RA = counter_RA + 1
With TabData.DataTable
.AddItem Sheets(Sheet1).Range(Cells(x + 2, 1), Cells(x + 2, LastColRA)).Text
End With
End If
Next x
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then
counter = counter + 1
With TabData.DataTable
.AddItem Sheets(Sheet2).Range(Cells(i + 2, 1), Cells(i + 2, LastColCP)).Text
End With
End If
Next i
End Sub
You have a couple of issues there. First, if you use the Text property of a multiple cell range, it will return Null unless all the cells contain the same text. Second, as you note, you cannot add an array in one go using AddItem - you need to add an item then loop to populate the columns, remembering that the indices are 0-based:
With TabData.DataTable
.AddItem
For n = 1 to LastColRA
.List(.ListCount - 1, n - 1) = Sheet1.Cells(x + 2, n).Value
next n
End With
Here's a version that will work with more than 10 columns:
Dim i As Long, counter As Long, counter_RA As Long, x As Long
Dim LastColRA As Long, LastColCP As Long
Dim vList()
LastColRA = Sheet1.Cells(1, Columns.Count).End(xlToLeft).Column
LastColCP = Sheet2.Cells(1, Columns.Count).End(xlToLeft).Column
'Check to make sure that enough items were selected
For x = 0 To ListBox2.ListCount - 1
If ListBox2.Selected(x) Then
counter_RA = counter_RA + 1
ReDim Preserve vList(1 To LastColRA, 1 To counter_RA)
For i = 1 To LastColRA
vList(i, counter_RA) = Sheet1.Cells(x + 2, i).Value
Next i
End If
Next x
For x = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(x) Then
counter_RA = counter_RA + 1
ReDim Preserve vList(1 To LastColRA, 1 To counter_RA)
For i = 1 To LastColRA
vList(i, counter_RA) = Sheet2.Cells(x + 2, i).Value
Next i
End If
Next x
With TabData.DataTable
.ColumnCount = LastColRA
.Column = vList
End With
I am using the following VBA code to insert a blank row where a sequential value is missing in excel.
Sub test()
Dim i As Long, x, r As Range
For i = Range("b" & Rows.Count).End(xlUp).Row To 2 Step -1
x = Mid$(Cells(i, "b"), 2) - Mid$(Cells(i - 1, "b"), 2)
If x > 1 Then
Rows(i).Resize(x - 1).Insert
Cells(i - 1, "b").AutoFill Cells(i - 1, "b").Resize(x), 2
End If
Next
This works fine unless the last value is missing.
For example I am filling in the blanks for groups of 5.
Where middle numbers are missing:
1
2
4
5
The code will insert a blank row for the missing value to become:
1
2
4
5
However if the last value, 5, was missing, a row will not be inserted.
So:
1
2
4
Becomes:
1
2
4
Is there a way to set a maximum to ensure the final value will be recognised as missing?
Try this...
Sub test()
Dim i As Long, x, r As Range, lMax As Long, lRw As Long
lRw = Range("b" & Rows.Count).End(xlUp).Row + 1
lMax = InputBox("Enter Maximum Value", "Maximum Input Req.", Application.Max(Range("B2:B" & lRw)))
For i = lRw To 2 Step -1
If i = lRw Then
x = lMax - Mid$(Cells(i - 1, "b"), 2)
If x > 1 Then
Cells(i - 1, "b").AutoFill Cells(i - 1, "b").Resize(x + 1), 2
End If
Else
x = Mid$(Cells(i, "b"), 2) - Mid$(Cells(i - 1, "b"), 2)
If x > 1 Then
Rows(i).Resize(x - 1).Insert
Cells(i - 1, "b").AutoFill Cells(i - 1, "b").Resize(x), 2
End If
End If
Next
End Sub
Revised Code
Sub test()
Dim i As Long, x, r As Range, lMax As Long, lRw As Long
lRw = Range("b" & Rows.Count).End(xlUp).Row + 1
lMax = InputBox("Enter Maximum Value", "Maximum Input Req.", Application.Max(Range("B2:B" & lRw)))
For i = lRw To 2 Step -1
If i = lRw Then
x = lMax - Cells(i - 1, "b").Value
If x > 1 Then
Cells(i - 1, "b").AutoFill Cells(i - 1, "b").Resize(x + 1), 2
End If
Else
x = Cells(i, "b").Value - Cells(i - 1, "b").Value
If x > 1 Then
Rows(i).Resize(x - 1).Insert
Cells(i - 1, "b").AutoFill Cells(i - 1, "b").Resize(x), 2
End If
End If
Next
End Sub
This answer was given to me on another forum:
http://www.ozgrid.com/forum/showthread.php?t=200184&goto=newpost**
Sub Reply()
i = 1
Do While Cells(i, 2) <> ""
j = Cells(i + 1, 2).Value - Cells(i, 2).Value - 1
If j < 0 Then j = 8 - Cells(i, 2).Value + Cells(i + 1, 2).Value
For k = 1 To j
Rows(i + k).EntireRow.Insert
Next k
i = i + k
Loop
End Sub
I need a macro to exports combinations from a range of many sets of values .
The sets of exporting combs will be smaler than the data range sets .
For examble lets say that i need all 2 set of values combinations of a 3 set of values in a data range .
DATA____ EXPORT
A B C____ AB AC BC
B B A____ BB BA BA
-
All the values of the data will be in different cels each one but the combs values must be in one cell each time.
Also the exports must be in horizontial as the example .
This is a code that ifound on web little close for me , but i cannot edit this to use it .
enter code here
Sub comb()
Dim vElements As Variant, vresult As Variant
Dim lRow As Long, i As Long
vElements = Application.Transpose(Range("A1", Range("A1").End(xlDown)))
Columns("C:Z").Clear
lRow = 1
For i = 1 To UBound(vElements)
ReDim vresult(1 To i)
Call CombinationsNP(vElements, i, vresult, lRow, 1, 1)
Next i
End Sub
Sub CombinationsNP(vElements As Variant, p As Long, vresult As Variant, lRow As Long,
iElement As Integer, iIndex As Integer)
Dim i As Long
For i = iElement To UBound(vElements)
vresult(iIndex) = vElements(i)
If iIndex = p Then
lRow = lRow + 1
Range("C" & lRow).Resize(, p) = vresult
Else
Call CombinationsNP(vElements, p, vresult, lRow, i + 1, iIndex + 1)
End If
Next i
End Sub
Thank you very much and sorry for my english .
I wonder if it was more convenient to use a new Sheet/ Range with cell reference
((= Sheet1! $A1 & Sheet1! B1)) this is three lines then copy
Sub Sub export_01()
Dim aStart, aExport
Dim aRow As Integer
aRow = ActiveSheet.Range("A65536").End(xlUp).Row
aStart = 1
aExport = 5
For i = 1 To aRow
Cells(i, aExport).Value = Cells(i, aStart) & Cells(i, aStart + 1)
Cells(i, aExport + 1).Value = Cells(i, aStart) & Cells(i, aStart + 2)
Cells(i, aExport + 2).Value = Cells(i, aStart + 1) & Cells(i, aStart + 2)
Next i
End Sub()
This seems to me simply use a second for loop
dim aStartend = 1
For i = 1 To aRow
For ii = 0 To 5 ' starts whist 0 to 5 = 6 time
Cells(i, aExport+ii).Value = Cells(i, aStart) & Cells(i,aStartend + ii)
--
--
next ii
next i
Bit of a complicated task I have to do but I will try and explain. I have an excel file with 23000 lines of data which I am importing into a website. Each one has a field like so:
Category | other data | other data 2
Foods/Dog/Treats Pre-Pack | 1223 | image.jpg
I need it to grab each line and add a new line below it for each "/" so turning the above into:
Category | other data | other data 2
[blank in original line] | 1223 | image.jpg
Foods | [blank field] | [blank field]
Foods/Dog | [blank field] | [blank field]
Foods/Dog/Treats Pre-Pack | [blank field] | [blank field]
So the script needs to add a new line for each category but keeping the original category in front of it. So turning category/category2/category 3 into 4 lines of: [blank] - category - category/category2 - category/category2/category 3
Does anyone know a way or script to do this?
Thanks, Simon
Note: The worksheet is called "test" and the category column starts at E2 and goes to E23521
I have the following script:
Sub test()
Dim a, i As Long, ii As Long, e, n As Long
Dim b(), txt As String, x As Long
With Range("a1").CurrentRegion
a = .Value
txt = Join$(Application.Transpose(.Columns(5).Value))
With CreateObject("VBScript.RegExp")
.Global = True
.Pattern = "/"
x = .Execute(txt).Count * 2
End With
ReDim b(1 To UBound(a, 1) + x, 1 To UBound(a, 2))
For i = 1 To UBound(a, 1)
If a(i, 5) <> "" Then
For Each e In Split(a(i, 5), "/")
n = n + 1
For ii = 1 To UBound(a, 2)
b(n, ii) = a(i, ii)
Next
b(n, 5) = Trim$(e)
Next
End If
Next
.Resize(n).Value = b
End With
End Sub
This seems to create a new row as I need it to but does not keep the slash structuring moving up with each one. And also dosnt add a blank line on all the new ones and make the original category value blank.
SOLVED:
Sub splitEmUp()
Dim splitter() As String 'this is storage space for the split function
Dim i As Integer ' main-loop for counter "which cell we are on"
Dim j As Integer ' splitter for-loop counter "which section of the split are we on"
Range("E2").Activate 'starting in cell e2 because row 1 is headers and category is located in the B column
For i = 0 To 24000 'from beginning to end i=0 means e2, i=1 means e3
ActiveCell.Offset(i, 0).Value = Replace(ActiveCell.Offset(i, 0).Value, " / ", "!##")
splitter = Split(ActiveCell.Offset(i, 0), "/") 'split the cell based on / and store it in splitter
If (UBound(splitter)) > 0 Then 'if a split occurred
ActiveCell.Offset(i, 0).Value = "" 'set the activecell to blank
Debug.Print i
ActiveCell.Offset(i + 1, 0).EntireRow.Insert shift:=xlDown, copyorigin:=xlFormatFromLeftOrAbove 'insert a new row and shift everything down
ActiveCell.Offset(i + 1, 0).Value = splitter(0) 'initialize the "Down" cells
ActiveCell.Offset(i + 1, 0).Value = Replace(ActiveCell.Offset(i + 1, 0).Value, "!##", " / ")
For j = 1 To UBound(splitter)
ActiveCell.Offset(i + j + 1).EntireRow.Insert shift:=xlDown, copyorigin:=xlFormatFromLeftOrAbove 'create another row if it needs to
ActiveCell.Offset(i + (j + 1), 0).Value = ActiveCell.Offset(i + j).Value & "/" & splitter(j) 'fill out the new row
ActiveCell.Offset(i + (j + 1), 0).Value = Replace(ActiveCell.Offset(i + (j + 1), 0).Value, "!##", " / ")
Next
i = i + UBound(splitter) + 1 'need to step I past the new cells
ReDim splitter(0)
Erase splitter 'erase and eliminate splitter to avoid carry over.
End If
Next
End Sub
This is what I came up with. Be sure to change the sheet names to fit your workbook. Also be sure to change the input range to fit your own input range of cells.
Function SplitAndWrite(inputCell As Range, TopOfOutputRange As Range, sep As String) As Range
Dim texts() As String, i As Integer, outputText As String
texts = Split(inputCell.Value, sep)
outputText = ""
TopOfOutputRange = "" 'your blank line
For i = LBound(texts) To UBound(texts)
outputText = outputText & sep & texts(i)
TopOfOutputRange.Offset(i + 1) = outputText
Next i
Set SplitAndWrite = TopOfOutputRange.Offset(UBound(texts) + 1)
End Function
Sub THEPOPULATOR()
Dim s3 As Worksheet, s4 As Worksheet
Set s3 = Sheets("Sheet1")
Set s4 = Sheets("Sheet2")
Dim inputrange As Range, c As Range, outputrange As Range
Set outputrange = s4.Range("A1")
Set inputrange = s3.Range(s3.Cells(2, 1), s3.Cells(2, 1).End(xlDown)) 'cells(2,1) = "A1". change this to your top input cell. then the second half will find the bottom cell on its own. This is the same as pressing Ctrl+down
For Each c In inputrange
s3.Range(c.Offset(0, 1), c.Offset(0, c.End(xlToRight).Column)).Copy outputrange.Offset(1, 1)
Set outputrange = SplitAndWrite(c, outputrange.Offset(1), "/")
Next c
End Sub
Here is an example from another solution How to split cell in a row with Excel, which I modified just a tiny bit to fit your situation:
Public Sub solutionJook()
Dim arr() As Variant
Dim arrSum() As Variant
Dim arrResult() As Variant
Dim arrTemp As Variant
Dim i As Long
Dim j As Long
Dim h As Long
Dim lngSplitColumn As Long
'input of array to seperate -> should cover all columns+rows of your data
arr = Range("A1:C2")
'specify which column has the values to be split up -> here this is the category column
lngSplitColumn = 2
'using the boundries of the given range,
'arrSum has now always the right boundries for the first dimension
ReDim Preserve arrSum(LBound(arr, 2) To UBound(arr, 2), 1 To 1)
'create the array with seperated A B C
For i = LBound(arr, 1) To UBound(arr, 1)
'use split to make Foods/Dog/Treats Pre-Pack into an array, using '\' (chr(92)) as indicator
arrTemp = Split(arr(i, lngSplitColumn), Chr(92))
'every value of arrTemp creates a new row
For j = LBound(arrTemp) To UBound(arrTemp)
'loop through all input columns and create the new row
For h = LBound(arr, 2) To UBound(arr, 2)
If h = lngSplitColumn Then
'setup the value of the splitted column
Dim k as long
arrSum(h, UBound(arrSum, 2)) = arrTemp(LBound(arrTemp))
for k = LBound(arrTemp)+1 to j
arrSum(h, UBound(arrSum, 2)) = arrSum(h, UBound(arrSum, 2)) & "\" & arrTemp(k) 'set Foods Foods/Dog Foods/Dog/Treats Pre-Pack
next k
Else
'setup the value of any other column
arrSum(h, UBound(arrSum, 2)) = arr(i, h) 'set Value of Column h
End If
Next h
ReDim Preserve arrSum(LBound(arr, 1) To UBound(arr, 2), _
LBound(arrSum, 2) To (UBound(arrSum, 2) + 1))
Next j
Next i
'clean up last empty row (not realy necessary)
ReDim Preserve arrSum(LBound(arr, 1) To UBound(arr, 2), _
LBound(arrSum, 2) To (UBound(arrSum, 2) - 1))
'setup transposed result array
ReDim arrResult(LBound(arrSum, 2) To UBound(arrSum, 2), _
LBound(arrSum, 1) To UBound(arrSum, 1))
'transpose the array
For i = LBound(arrResult, 1) To UBound(arrResult, 1)
For j = LBound(arrResult, 2) To UBound(arrResult, 2)
arrResult(i, j) = arrSum(j, i)
Next j
Next i
'specify target range
Range(Cells(1, 5), Cells(UBound(arrResult, 1), 4 + UBound(arrResult, 2))) = arrResult
End Sub
You might need to adapt the target range however.
Cells(1,5) -> E1 is the starting point of pasting