Excel: How to split a column into two columns based off a third, odd/even parameter column? - vba

I will be referencing the below picture:
I seek to split up the FirstValue Column into the two columns right of it; however, I want to split the columns based off the Parameter column. When the Parameter value is odd, I want to copy the values only to the OtherValue1 column. When the Parameter value is even, I want to copy the values only to the OtherValue2 column. After reading forums and trying excel's "Text to Columns" feature, I am unable to find a solution.
Is there a way implement this using VBA?
*Note: The worksheet is actually about 10,000 rows long, so speed would also be helpful.
EDIT:
Here is the code I have so far. I am getting Object errors in this line of code: .Cells(2, MF1Col).Formula = "=IF(MOD(paraformula,2)=1,WTRfor,"")"
Dim rw As Worksheet
Dim secondCell, MF1Cell, MF2Cell, paraCell, MF1formula, MF2formula, paraformula, WTRfor As Range
Dim secondCol As Long, MF1Col As Long, MF2Col As Long, paraCol As Long
Set rw = ActiveSheet
With rw
Set secondCell = .Rows(1).Find("FirstValue”)
' Check if the column with “FirstValue” is found
'Insert Two Columns after FirstValue
If Not secondCell Is Nothing Then
secondCol = secondCell.Column
.Columns(secondCol + 1).EntireColumn.Insert
.Columns(secondCol + 2).EntireColumn.Insert
.Cells(1, secondCol + 1).Value = "OtherValue1"
.Cells(1, secondCol + 2).Value = "OtherValue2"
.Activate
Set MF1Cell = .Rows(1).Find("OtherValue1")
MF1Col = MF1Cell.Column
Set MF2Cell = .Rows(1).Find("OtherValue2")
MF2Col = MF2Cell.Column
Set paraCell = .Rows(1).Find("Parameter")
paraCol = paraCell.Column
Set paraformula = Range(.Cells(2, paraCol).Address(RowAbsolute:=False, ColumnAbsolute:=False))
Set MF1formula = Range(.Cells(2, MF1Col).Address(RowAbsolute:=False, ColumnAbsolute:=False))
Set WTRfor = Range(.Cells(2, secondCol).Address(RowAbsolute:=False, ColumnAbsolute:=False))
.Cells(2, MF1Col).Formula = "=IF(MOD(" & paraformula & ",2)=1," & WTRfor & ","""")"
Range(.Cells(2, MF1Col).Address).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
ActiveSheet.Paste
Set MF2formula = Range(.Cells(2, MF2Col).Address(RowAbsolute:=False, ColumnAbsolute:=False))
.Cells(2, MF2Col).Formula = "=IF(MOD(" & paraformula & ",2)=0," & WTRfor & ","""")"
Range(.Cells(2, MF2Col).Address).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
ActiveSheet.Paste
End If
End With

in C2, =IF(MOD(E2,2)=1,B2,"")
in D2, =IF(MOD(E2,2)=0,B2,"")
copy these down to the end of your data
assuming the same format (Data,Col1,Col2,Parameter), but using relative addressing
Column 1: =IF(MOD(OFFSET(C2,0,2),2)=1,OFFSET(C2,0,-1),"") replace C2 with the current cell
Column 2: =IF(MOD(OFFSET(D2,0,1),2)=0,OFFSET(D2,0,-2),"") replace D2 with the current cell
again, copy and paste - once you have the first one correct, excel will adjust the formula for the current cell

For Cell D2:
=IF(MOD(E2,2),B2,"")
Explanation:
If Range E2 is not divisible by two, the display value from B2, otherwise display nothing.
you can reverse this by inserting a 'NOT' around the MOD for Cell C2:
=IF(NOT(MOD(E2,2)),B2,"")

VBA:
Sub odd_even()
a = 1 ' start row
b = 10 ' end row
c = 1 ' column with values inputs
For d = a To b ' FOR loop from start row to end row
If ActiveSheet.Cells(d, c) Mod 2 Then 'mod becomes high when value is odd
ActiveSheet.Cells(d, c + 2) = ActiveSheet.Cells(d, c) 'odd value gets copied to the odd-column ( two to the right of the values)
ActiveSheet.Cells(d, c + 3) = "" 'same row on even-column gets cleared
Else:
ActiveSheet.Cells(d, c + 3) = ActiveSheet.Cells(d, c) 'even value gets copied to the even-column ( three to the right of the values)
ActiveSheet.Cells(d, c + 2) = "" 'same row on odd-column gets cleared
End If
Next d ' go to next row
End Sub

Related

Copying row to another sheet and create unique code for duplicate

I would like to know how to manipulate my excel data as I need.
I have a table with rows and a lot of field I would like to select by hand some rows and to copy them to another sheet that has predefined column ordering those rows to fit my predefined column and to create an unique code for rows that I consider duplicate based on 2 two column.
This might not be very clear so I will explain more with photo:
here I have my table with rows I selected by hand, I would like to copy column H,I,K,AA,AJ to another sheet but in some specific order to fit my other table column:
I would like my AJ column in the Column A, my AA column in the Column E My column K in the Column F etc...
I Would also want to create a unique Key based on column F and I (for example here in the first image rows 17 to 21 would have the same key in the blue sheet in column B)
For the moment I am able to take my selected rows and copy the wanted column to another sheet.
I don't know how to reorder them to fit my template in the second sheet. I also don't know how to create a key and insert it to my second sheet for each combination of columns F and I of my first sheet.
Sub ajout_commande()
Set DataSheet = ThisWorkbook.Worksheets("0")
Dim a As Range, b As Range
Set a = Selection
i = Selection.Rows.Count
For Each b In a.Rows
DataSheet.Cells(2, 1).EntireRow.Insert
Next
Dim r1 As Range, r2 As Range, r3 As Rang, r4 As Range, r5 As Range, res_range As Range
Let copyrange1 = "I1" & ":" & "I" & i
Let copyrange2 = "K1" & ":" & "K" & i
Let copyrange3 = "L1" & ":" & "L" & i
Let copyrange4 = "AA1" & ":" & "AA" & i
Let copyrange5 = "AJ1" & ":" & "AJ" & i
Set r1 = a.Range(copyrange1)
Set r2 = a.Range(copyrange2)
Set r3 = a.Range(copyrange3)
Set r4 = a.Range(copyrange4)
Set r5 = a.Range(copyrange5)
Set res_range = Union(r1, r2, r3, r4, r5)
res_range.Copy
DataSheet.Cells(2, 1).PasteSpecial xlPasteValues
End Sub
If this is to complicate to implement or impossible please tell me in comment so that I try to find another method. I am new to VBA and am trying to help my colleagues by simplifying their work.
Thanks.
Maybe try something like this.
It need some adjustements (especially in cells to copy)
Dim UniqueKeyArray() As String
Dim Counter As Long
Sub test()
Dim aRows As Range, aCell As Range
Dim Ws As Worksheet
Dim i As Long
Set Ws = ThisWorkbook.Sheets("SomeName")
ReDim UniqueKeyArray(0 To 1, 1 To 1)
For i = 1 To Selection.Areas.Count 'loop through selection
For Each aRows In Selection.Areas(i).Rows 'loop through rows of selection
For Each bCell In aRows.Columns(1).Cells 'loop through cells in column one
With Ws
.Cells(2, 1).EntireRow.Insert
'adjust offset to get source data you need
'adjust cells(x,y) to put data where you want it
.Cells(2, 2) = bCell.Offset(0, 2)
.Cells(2, 3) = bCell.Offset(0, 3)
.Cells(2, 4) = bCell.Offset(0, 5)
.Cells(2, 5) = bCell.Offset(0, 6)
.Cells(2, 1) = "'" & UniqueKey(bCell.Text) ' "'" added to prevent excel trim leading 000..
End With
Next bCell
Next aRows
Next i
'reset variables. This way you always start unique key from 1
Counter = 0
Erase UniqueKeyArray
End Sub
Function UniqueKey(SourceVal As String) As String
'creates unique key based on source string
Dim i As Long
For i = 1 To UBound(UniqueKeyArray, 2)
If UniqueKeyArray(1, i) = Format(SourceVal, "0000000000") Then
'if string is same you get unique key created before
UniqueKey = UniqueKeyArray(1, i)
Exit Function
End If
Next i
'if string is new then new unique key is created
Counter = Counter + 1
ReDim Preserve UniqueKeyArray(0 To 1, 1 To Counter)
UniqueKey = Format(Counter, "0000000000") 'adjust format to fit your needs
UniqueKeyArray(0, Counter) = SourceVal
UniqueKeyArray(1, Counter) = UniqueKey
End Function

How To Have VBA Insert Formula Result as a Value

I got help last week getting my syntax and ranges correct, and thought I could just do a vlookup to finish it but apparently I was mistaken. It just seems like when I try to research how to accomplish this, I find various examples but I don't have the background to translate it to my code.
The macro runs and does almost everything its supposed to do. But in addition to inserting the arrays, there are 3 other cells that need values when there are blank cells in my ‘sourcerng’.
This is the logic for the cells that need values (the values are already in my worksheet, I just need to get them to these blank cells). I tried to do an IIF statement for these but I still have no idea what I'm doing. Would that be the best way? Should it just be another IF THEN statement?
rngBE - IF Column Z = 0 Then copy value from corresponding row in column O. Otherwise copy value from column Z
rngBG - IF Column AA = "Unknown" Then copy value from corresponding row in column I. Otherwise copy value from column AA.
rngBK - IF Column AB = "Unknown" Then copy value from corresponding row in column N. Otherwise copy value from column AB.
Sub AutomateAllTheThings6()
Dim arr3() As String
Dim arr11() As String
'Dim resBE As String
Dim rng3 As Range
Dim rng11 As Range
Dim rngBE As Range
Dim rngBG As Range
Dim rngBK As Range
Dim sourcerng As Range
'Dim firstRow As Long
Dim lastRow As Long
'Dim i As Long
Call OptimizeCode_Begin
'firstRow = 2
lastRow = ActiveSheet.Range("D1").End(xlDown).Row
Set rng3 = ActiveSheet.Range("BH2:BJ" & lastRow)
Set rng11 = ActiveSheet.Range("BL2:BV" & lastRow)
Set rngBE = ActiveSheet.Range("BE2:BE" & lastRow)
Set rngBG = ActiveSheet.Range("BG2:BG" & lastRow)
Set rngBK = ActiveSheet.Range("BK2:BK" & lastRow)
Set sourcerng = ActiveSheet.Range("BE2:BE" & lastRow)
arr3() = Split("UNKNOWN,UNKNOWN,UNKNOWN", ",")
arr11() = Split("UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN,00/00/0000, _
00/00/0000,00/00/0000,00/00/0000,NEEDS REVIEW", ",")
For Each cell In sourcerng
If IsEmpty(cell) Then
Intersect(rng3, ActiveSheet.Rows(cell.Row)).Value = arr3
Intersect(rng11, ActiveSheet.Rows(cell.Row)).Value = arr11
'***PLS HELP***
Intersect(rngBE, ActiveSheet.Rows(cell.Row)).Value = "WEEEEE"
Intersect(rngBG, ActiveSheet.Rows(cell.Row)).Value = "WOOOOO"
Intersect(rngBK, ActiveSheet.Rows(cell.Row)).Value = "WAAAAA"
End If
Next
Range("BR2:BU2").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.NumberFormat = "mm/dd/yyyy"
Columns("BF:BF").Select
Selection.Delete Shift:=xlToLeft
Call OptimizeCode_End
End Sub
'*********TESTING***********
'resBE = IIf(Cells(13,Z).Value = 0, Cells(13,BE).Value = Cells(13,Z), Cells(13,BE).Value = Cells(13,O))
'***************************************
'For i = firstRow To lastRow
' valZ = Range("Z" & i)
' valOh = Range("O" & i)
'
' If valZ = 0 Then
' rngBE.Value = valOh
' Else rngBE.Value = valZ
' End If
There are several ways to do your task. If you're more of an "Excel" person than VBA you might consider this approach: You can inject the syntax of any "regular" formula in R1C1 Format.
So the formula mentioned above =if($Z2=0,$O2,$Z2) is .FORMULA format for any value in row 2.
But in .FORMULAR1C1 it can be inserted in ANY cell as: =IF(RC26=0,RC15,RC26) (basically no rows up or down, but always columns O (15) and Z(26).
So, your modified code would have something like this:
Intersect(rngBE, ActiveSheet.Rows(cell.Row)).FormulaR1C1 = "=IF(RC26=0,RC15,RC26)"
Intersect(rngBE, ActiveSheet.Rows(cell.Row)).Value = _
Intersect(rngBE, ActiveSheet.Rows(cell.Row)).Value
Again, this is NOT the most efficient way to accomplish your task, but if you're dealing with thousandsof rows, versus tens to hundreds of thousands, I wouldn't worry about it and it gives you a new tool to use.

Using Vlookup In VBA With Filter Conditions

What I am trying to accomplish here is
1) Is to iterate the values in column O and for the ones that are not null - filter the worksheet titled DATA to only show values where Column B = X and use VLOOKUP() to return the lookup values to the corresponding row in Column P
2) If column O is null then filter the sheet titled DATA to only show values where Column B <> X and use VLOOKUP() to return the lookup values to the corresponding row in Column P.
I attempted the syntax below but I am getting an error of
Method 'Rarnge' of object '_Worksheet' failed
What do I need to do differently in my code below to get the syntax to return the values I desire?
Dim destSheet As Worksheet: Set destSheet = Sheets("Main")
For i = Range("A" & Rows.Count).End(3).Row To 2 Step -1
If Not IsEmpty(Cells(i, "O").Value) Then
Sheets("Data").Select
Selection.AutoFilter
ActiveSheet.Range("$A:$C").AutoFilter Field:=2, Criteria1:="<>"
Sheets("Main").Select
Application.CutCopyMode = False
form2 = "=IFERROR(VLOOKUP(RC[-15],Lookup!C[-15]:C[-13],3,FALSE),"""")"
destSheet.Range("P:P" & lr).Formula = form2
Else
Sheets("Data").Select
Selection.AutoFilter
Sheets("Main").Select
Application.CutCopyMode = False
form3 = "=IFERROR(VLOOKUP(RC[-15],Lookup!C[-15]:C[-13],3,FALSE),"""")"
destSheet.Range("P:P" & lr).Formula = form3
End If
Next i
It was a bit hard to understand for me what you are trying to do, please correct me if I get you wrong.
First of all selecting sheets is not a preferred method while running macros, unless you intentionally do it, so avoid it.
Secondly, you don't need to filter anything, you can control it by checking conditions within your code. You don't do things physically, you do them theoretically within your code, and display the output.
Have a look at this code and ask wherever you need help to understand.
Sub VLookups()
Dim destSheet As Worksheet: Set destSheet = Sheets("Main")
Dim i As Long
Dim myVal As Variant
Set lookupRange = Sheets("Data").Range("$A:$C") 'This is your lookup range
For i = 2 To Range("O" & Rows.Count).End(xlUp).Row 'Iterate from 2nd row till last row
myVal = Application.VLookup(destSheet.Cells(i, "A").Value, lookupRange, 2, False)
If IsError(myVal) Then GoTo Skip 'If searched value not found then skip to next row
If Not IsEmpty(Cells(i, "O").Value) Then 'If Cell in Column O not empty
If myVal = "YOUR X VALUE FOR COLUMN B" Then 'If Your Column B X value exists
destSheet.Cells(i, "P").Value = Application.VLookup(destSheet.Cells(i, "A").Value, _
lookupRange, 3, False) 'Column P Cell is populated by Data Sheet Column C Cell
End If
Else 'If Cell in Column O empty
If myVal <> "YOUR X VALUE FOR COLUMN B" Then 'If Your Column B X value not exists
destSheet.Cells(i, "P").Value = Application.VLookup(destSheet.Cells(i, "A").Value, _
lookupRange, 3, False) 'Column P Cell is populated by Data Sheet Column C Cell
End If
End If
Skip:
Next i
End Sub

Fill empty cells between two filled cells

The Situation:
On the Cell "A1" I have the value "1"
On the Cell "A10" I have the value "2"
On the Cell "A20" I have the value "3"
On the Cell "A30" I have the value "4"
What I want to do with Excel VBA:
Between A1 and A10 there are empty cells. I want that A2:A9 is filled with the value of A10, that means "2".
Between A10 and A20 there are empty cells. I want that A11:19 is filled with the value of A20, that means "3".
The problem is, the range A1 to A30 is not fixed. I want to search the whole row for cells which are not empty and to fill the cells between them with the upper cell which is filled.
EDIT:
To explain more, I have an Access Database with a table which is filled with Dates and a table which is filled with numbers.
I want to make a Report to an Excel Sheet.
Dim Daten As Variant
Daten = Array(rs!DatumJMinus8Monate, rs!DatumJ, rs!DatumI, rs!DatumH, rs!DatumG, rs!DatumF, rs!DatumE, rs!DatumD, rs!DatumC, rs!DatumB, rs!DatumA, rs!DatumA4Monate)
Dim Bedarfe As Variant
Bedarfe = Array(rs!BedarfJ8Monate, rs!BedarfJ, rs!BedarfI, rs!BedarfH, rs!BedarfG, rs!BedarfF, rs!Bedarfe, rs!BedarfD, rs!BedarfC, rs!BedarfB, rs!BedarfA, rs!BedarfA, "")
Dim neuereintrag As Boolean
bedarfindex = 0
For Each element In Daten
i = 7
For jahre = 1 To 10
If Cells(1, i + 1) = Year(element) Then
For monate = 1 To 12
If Cells(2, i + monate) = Month(element) Then
Cells(zeile, i + monate) = Bedarfe(bedarfindex)
Cells(zeile, i + monate).Font.Bold = True
bedarfindex = bedarfindex + 1
neuereintrag = True
ElseIf IsEmpty(Cells(zeile, i + monate)) Or neuereintrag = True Then
Cells(zeile, i + monate) = Bedarfe(bedarfindex)
neuereintrag = False
End If
Next monate
End If
i = i + 12
Next jahre
Next element
In the picture the numbers in the red circles have to be deleted.
On way to work from the bottom upwards:
Sub FillUp()
Dim N As Long
Dim i As Long
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = N - 1 To 1 Step -1
If Cells(i, 1).Value = "" Then Cells(i, 1).Value = Cells(i + 1, 1).Value
Next i
End Sub
Maybe something like this. It needs a bit of work as it will fail if two values are next to each other, or column 1 doesn't contain a value.
Sub AutoFill()
Dim rCell1 As Range, rCell2 As Range
With ThisWorkbook.Worksheets("Sheet1")
'Find the last column containing data, set both references to this
'so the Do While doesn't fall over on the first loop.
Set rCell2 = .Cells(1, .Columns.Count).End(xlToLeft) '1 is the row number it's looking at.
Set rCell1 = rCell2
'Find next cell to the left containing data and fill between these two columns.
Do While rCell1.Column <> 1
Set rCell1 = rCell2.End(xlToLeft)
.Range(rCell1, rCell2.Offset(, -1)).FillRight
Set rCell2 = rCell1
Loop
End With
End Sub

VBA that copies rows into new sheet based on each row's cell contents (example included)

So I'm hoping for some help to automate a process that will otherwise involve copying and editing some 10,000 rows.
This is stuff relating to location data. Essentially, there are tons of these Master Rows but they do not have individual rows for Unit Numbers. I am hoping to get something to expand these into individual Unit Number rows based on what is in Column N. Column N is intended to follow a strict format of being a comma-seperated single cell list for each row.
Below is an example from Sheet 1 of what each row will have and needs to be expanded upon. Note that Column N is green and follows a consistent formatting and this will be the determinant for how many times these rows will each be expanded upon.
Below is Sheet 2 and what I want the VBA to create from Sheet 1. You can see that each row has been expanded based on the contents of Column N from Sheet 1.
Like I said, it is expected that this will involve some several thousand rows to create.
Option Explicit
Sub Tester()
Dim sht1, sht2, rwSrc As Range, rwDest As Range, v, arr, n
Set sht1 = ThisWorkbook.Sheets("Sheet1")
Set sht2 = ThisWorkbook.Sheets("Sheet2")
sht2.Range("A2:M2").Resize(3, 13).Value = sht1.Range("A2:M2").Value
Set rwDest = sht2.Range("A2:M2") 'destination start row
Set rwSrc = sht1.Range("A2:M2") 'source row
Do While Application.CountA(rwSrc) > 0
v = rwSrc.EntireRow.Cells(1, "N").Value 'list of values
If InStr(v, ",") > 0 Then
'list of values: split and count
arr = Split(v, ",")
n = UBound(arr) + 1
Else
'one or no value
arr = Array(v)
n = 1
End If
'duplicate source row as required
rwDest.Resize(n, 13).Value = rwSrc.Value
'copy over the unit values
rwDest.Cells(1, "G").Resize(n, 1).Value = Application.Transpose(arr)
'offset to next destination row
Set rwDest = rwDest.Offset(n, 0)
'next source row
Set rwSrc = rwSrc.Offset(1, 0)
Loop
End Sub
This does the work in same sheet... Pls copy the value to "Sheet2" before executing this. Not sure about efficiency though.
Public Sub Test()
Dim lr As Long ' To store the last row of the data range
Dim counter As Long
Dim Str As String ' To store the string in column N
lr = Range("N65536").End(xlUp).Row 'Getting the last row of the data
For i = lr To 2 Step -1
Str = Range("N" & i).Value ' Getting the value from Column N
counter = 1
For Each s In Split(Str, ",")
If counter > 1 Then
Range("A" & (i + counter - 1)).EntireRow.Insert ' Inserting rows for each value in column N
Range("G" & (i + counter - 1)).Formula = s ' Updating the value in Column G
Else
Range("G" & i).Formula = s ' No need to insert a new row for first value
End If
counter = counter + 1
Next s
Next i
lr = Range("G65536").End(xlUp).Row
' Pulling down other values from the first value row other rows
Range("A1:N" & lr).Select
Selection.SpecialCells(xlCellTypeBlanks).Select
Selection.FormulaR1C1 = "=R[-1]C"
' Pasting the data as Values to avoid future formula issues.
Range("A1:N" & lr).Copy
Range("A1:N" & lr).PasteSpecial xlPasteValues
MsgBox "Done"
End Sub