Fill in Column with values from another column if statement(s) - excel

I currently have a VBScript that takes in an Excel document and re-formats it into another Excel document that's more organized.
This code must also look at the values of the CATALOG column ("B1") and place it in the Drawings column ("M1") ONLY if the beginning of the value starts with "EDASM", "EDBSM" etc., yet the "ED" prefix must be eliminated when it's moved.
For example, Catalog number EDF12-01114 would result in nothing being placed in the drawings column, but with EDSM10265, we would need SM10265 to be placed in the drawings column (drop the "ED").
All I've got so far is this, which isn't even complete:
Set objRange = objWorkSheet.Range("M1").EntireColumn
IF
objWorkSheet.Range("B1").Row = "EDF*" THEN 'Maybe correct-ish? Not sure about syntax
objRange = Null
Else
objRange = ("B1") 'Totally an awful guess, but I have no clue what to put here
End If
I've seen similar code that has loops and whatnot, but none of them seem to be doing what I need to be done. Thank you!
EDIT: Current code based off of BruceWayne's. Still doesn't return anything in Excel datasheet's Drawing column, but it looks like it's closer...
Sub move_Text()
Dim lastRow, nextRow, cel , rng
lastRow = Cells(Rows.Count, 2).End(xlUp).Row ' Since your Col. B is the data, let's find that column's last row
Set rng = Range(Cells(1, 2), Cells(lastRow, 2))
nextRow = 1
For Each cel In rng
If Left(cel.Value, 3) <> "EDF" Then
Cells(nextRow, 13).Value = Mid(cel.Value, 3, Len(cel.Value) - 2)
nextRow = nextRow + 1
End If
Next
End Sub
Another edit!
Catalog column is now "C", not "B". Also, I have two header rows, so the first catalog number is located in "C3".
Thanks again! We're getting closer.
Here's the Google Drive files: https://drive.google.com/folderview?id=0B2MeeQ3BKptFYnZfQWpwbTJxMm8&usp=sharing
IMPORTANT TO REMEMBER
In the Google Drive files: TestScript.vbs is the file where all the code is. When the script is run, select ExcelImport. That should return FinalDocument

I guess this is what you are looking for:
Sub move_Text()
Dim lastRow, nextRow, cel, rng
'get last row with data in Column B
lastRow = Cells(Rows.Count, "B").End(xlUp).Row
'set your range starting from Cell B2
Set rng = Range("B2:B" & lastRow)
'loop through all the cells in the range to check for "EDF" and "ED"
For Each cel In rng
'below condition is to check if the string starts with "EDF"
If cel.Value Like "EDF*" Then
'do nothing
'below condition is to check if the string starts with "ED"
ElseIf cel.Value Like "ED*" Then
'drop first two characters of cell's value and write in Column M
cel.Offset(0, 11).Value = Right(cel.Value, Len(cel.Value) - 2)
'else condition will be executed when none of the above two conditions are satisfied
'else condition is based on the link mentioned in your question that will handle words like "ELECTRICAL BOX"
Else
'write cell's value in Column Q
cel.Offset(0, 11).Value = cel.Value
End If
Next
End Sub
EDIT : For VBScirpt
________________________________________________________________________________
Sub Demo()
Dim lastRow, nextRow, cel, rng
Const xlShiftToRight = -4161
Const xlUp = -4162
Const xlValues = -4163
Const xlWhole = 1
Const xlPrevious = 2
With objWorksheet
'get last row with data in Column B
lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row
'set your range starting from Cell B2
Set rng = .Range("C2:C" & lastRow)
End With
'loop through all the cells in the range to check for "EDF" and "ED"
For Each cel In rng
'below condition is to check if the string starts with "EDF"
If InStr(1, cel.Value, "EDF", 1) = 1 Then
'do nothing
'below condition is to check if the string starts with "ED"
ElseIf InStr(1, cel.Value, "ED", 1) = 1 Then
'drop first two characters of cell's value and write in Column M
cel.Offset(0, 10).Value = Right(cel.Value, Len(cel.Value) - 2)
'else condition will be executed when none of the above two conditions are satisfied
'else condition is based on the link mentioned in your question that will handle words like "ELECTRICAL BOX"
Else
'write cell's value in Column M
cel.Offset(0, 10).Value = cel.Value
End If
Next
End Sub

How's this work for you?
Sub move_Text()
Dim lastRow&, nextRow&
Dim cel As Range, rng As Range
lastRow = Cells(Rows.Count, 2).End(xlUp).Row ' Since your Col. B is the data, let's find that column's last row
Set rng = Range(Cells(1, 2), Cells(lastRow, 2))
nextRow = 1
For Each cel In rng
If Left(cel.Value, 2) = "ED" Then
Cells(nextRow, 13).Value = Mid(cel.Value, 3, Len(cel.Value) - 2)
nextRow = nextRow + 1
End If
Next cel
End Sub
It will set the range to be your Column B, from row 1 to the last row. Then, loop through each cell in there, checking the left two letters. If "ED", then move the data, but take off the "ED".
Edit: Just realized you're using VBScript. Remove the as Range and & from the declarations, so it's just Dim lastRow, nextRow, cel, rng.

If your criteria is met, this will copy values (minus the ED prefix) from Column B to Column M.
Sub move_Text()
Dim lastRow , i
lastRow = Cells(Rows.Count, 3).End(xlUp).Row
For i = 3 To lastRow
If Left(Cells(i, 3), 2) = "ED" And Not (Left(Cells(i, 3), 3) = "EDF") Then
Cells(i, 13).Value = Right(Cells(i, 3, Len(Cells(i, 3)) - 2)
End If
Next
End Sub

Why not use some of excel's formulas to speed the whole thing up:
Sub My_Amazing_Solution ()
Range("M3").FormulaR1C1 = "=IF(TRIM(LEFT(RC[-10],2))=""ED"",RIGHT(TRIM(RC[-10]),LEN(RC[-10])-2),"""")"
Range("M3").AutoFill Destination:=Range("M3:M" & Range("C1048576").End(xlUp).Row), Type:=xlFillDefault
Application.Wait Now + TimeValue("00:00:03")
Range("M3:M" & Range("C1048576").End(xlUp).Row).Copy
Range("M3").PasteSpecial xlPasteValues
End sub
This should do it for you!

Related

Split zip code in a column into 2 columns

This is what my end result should look like. If there is not the four digits to move over to the second column then fill with 4 zeros.
How can I split zip code in a column into 2 columns and fill empty cells in column 2 if first column has only 5 digits?
Here is what I have been working with
Dim ws As Worksheet
Dim cell As Range
Set ws = Worksheets("sheet1")
For Each cell In ws.Range("K2:K500").Cells
cell.Offset(0, 1).Value = Left(cell.Value, 5)
Next cell
Dim cel As Range, rngC As Range, rngB As Range
Dim lastRowA As Long, lastRowB As Long
With ws
lastRowK = .Cells(.Rows.Count, "K").End(xlUp).Row 'last row of column A
lastRowL = .Cells(.Rows.Count, "L").End(xlUp).Row 'last row of column B
For Each cel In .Range("K2:K" & lastRowL) 'loop through column L
'check if cell in column A exists in column B
If WorksheetFunction.CountIf(.Range("K2:K" & lastRowL), cel) = 0 Then
cel.Offset(0, 3).Value = Right(cel.Value, 4)
'.Range("M" & cel.Row) = Right(cell.Value, 4)
Else
.Range("M" & cel.Row) = "0000"
End If
Next
End With
In case you want to bypass VBA and use formulas, you can do this.
Cell B2:
=LEFT(A2,5)
Cell C2:
=IF(LEN(A2)=9,RIGHT(A2,4),"0000")
One of the simplest ways to solve this problem is to supplement the original string with a large number of zeros and take the values ​​of the first and second five characters for two cells:
Sub setZIPandZeros()
Const TEN_ZEROS = "0000000000" ' 10 times
Dim ws As Worksheet
Dim cell As Range
Dim sLongString As String
Set ws = Worksheets("Sheet1")
For Each cell In ws.Range("K2:K" & ws.Cells(ws.Rows.Count, "K").End(xlUp).Row).Cells
sLongString = Trim(cell.Text) & TEN_ZEROS
cell.Offset(0, 1).Resize(1, 2).NumberFormat = "#"
cell.Offset(0, 1).Resize(1, 2).Value = Array(Left(sLongString, 5), _
Mid(sLongString, 6, 5))
Next cell
End Sub
Update The modified code is much faster and gives a result that more closely matches the description of the task:
Sub setZipZeros()
Dim ws As Worksheet
Dim rResult As Range
Set ws = Worksheets("Sheet1")
' Addressing R1C1 is used in the formulas - If the original range
' is shifted to another column, you will need to change the letter
' of the column "K" only in this line
Set rResult = ws.Range("K2", ws.Cells(ws.Rows.Count, "K").End(xlUp)).Offset(0, 1)
' If the columns L:M are already in text format, then instead of
' the results we will get the texts of formulas
rResult.Resize(, 2).NumberFormat = "General"
' These two lines do most of the work:
rResult.Formula2R1C1 = "=LEFT(TRIM(RC[-1])&""00000"",5)"
rResult.Offset(0, 1).Formula2R1C1 = "=MID(TRIM(RC[-2])&""000000000"",6,4)"
' We don't know if auto-recalculation mode is on now
' Application.Calculation = xlAutomatic
ActiveSheet.Calculate
Set rResult = rResult.Resize(, 2)
' Set the text format for the cells of the result
' to prevent conversions "00123" to "123"
rResult.NumberFormat = "#"
' Replace formulas with their values
rResult.Value = rResult.Value
End Sub

VBA Instr function on 100K+ records

I have 100.000 records/rows with 17 columns. One of these columns needs to be checked to output either a 1 or 0 to the next column. For this I use a loop with the Instr function, but after 10 mins it still isn't outputting anything on my machine and I believe the code is too intensive or slow running it row for row.
Dim rng As Range
Set rng = Range("F:F")
For Each cell In rng
TicketType = cell
If InStr(1, TicketType, "locker", 1) > 0 Then
cell.Offset(0, 1) = 1
Else
cell.Offset(0, 1) = 0
End If
Next
There are only 100 TicketTypes to check however, and based on the names of these TicketTypes it should output a 1 or 0 (match or not). So I was thinking, maybe there is a way to sort the entire table, run through it to see which categories there are, store their vertical ranges, run a check and then output +-10.000 rows at once? I noticed this is instant, so I believe it's really the Instr function that is the bottleneck.
Try this:
Dim rng As Range, f
With ActiveSheet
Set rng = Application.Intersect(.Columns("F"), .UsedRange)
f = "=--NOT(ISERROR(SEARCH(""locker""," & rng(1).Address(False, False) & ")))"
Debug.Print f
rng.Offset(0, 1).Formula = f
rng.Offset(0, 1).Value = rng.Offset(0, 1).Value
End With
Variant array approach
As mentioned by BigBen it's faster than looping through each cell by means of VBA.
Sub VariantArray()
With Sheet1
'~~> Set you relevant range here
Dim lastRow As Long, rng As Range
lastRow = .Range("F" & .Rows.Count).End(xlUp).Row
Set rng = .Range("F1:F" & lastRow)
'~~> create a one based 2-dim datafield array
Dim myArray As Variant
myArray = rng
'~~> check TicketType
Dim i As Long
For i = 1 To UBound(myArray)
myArray(i, 1) = IIf(InStr(1, myArray(i, 1), "locker", 1) > 0, 1, 0)
Next i
'~~> fill target with array values
rng.Offset(0, 1) = myArray
End With
End Sub
you could try filtering:
With Worksheets("actualSheetName") '<-- change "actualSheetName" to your actual sheet name
With .Range("F1", .Cells(.Rows.Count, "F").End(xlUp))
.Offset(, 1).Value = 0
.AutoFilter Field:=1, Criteria1:="*locker*"
.SpecialCells(xlCellTypeVisible).Offset(, 1) = 1
End With
.AutoFilterMode = False
End With
As suggested by BigBen, a far better solution is the usage of a worksheet function, like Find.All() (at least that how I think it's called). If it finds something, it gives a number, else it gives an error. You might turn this into an interesting formula like this:
=IF(IF.ERR(FIND.ALL("locker";A2);0)=0;0;1)

Moving every value in a certain to a certain cell

I have a list of contacts with over 4000 rows. Problem is every ID per person has been duplicated, each duplicated row stores the alternate contact details such mobile, work phone. What i need to do is make the unique 1d's in one column by the subsequent work, work2, home 2, mobile, mobile 2 etc on the same row rather it being below.
I was wondering if there was a way of doing, for every value in the work 2 telephone type, move to father work cell being (I2) in the screenshot.
As cut and pasting every cell to put them into their designated cells is to time consuming
Thank You.
Something like this would transpose your data, it creates a dummy column that count main id and which rows to delete.
VBA Code:
Sub TransposeData()
Dim ws As Worksheet
Dim lrow As Long
Dim i As Long
Dim j As Long
Dim myRange As Range
Dim cl As Variant
Dim count As Long
Dim cel As Range
Dim delRng As Range
Set ws = ActiveWorkbook.Worksheets("Sheet1") 'Set worksheet name
ws.Cells(1, 20).Value = "DelRC" 'dummy Column
lrow = ws.Cells(Rows.count, 1).End(xlUp).Row 'Find last row
Set myRange = Range(ws.Cells(2, 8), ws.Cells(lrow, 8)) 'Loop range
For Each cl In myRange 'Loop through range
If ws.Cells(cl.Row - 1, 3).Value = ws.Cells(cl.Row, 3).Value Then 'Check id - 1 = id
ws.Cells(cl.Row, 20).Value = 1 'Print dummy
ElseIf ws.Cells(cl.Row - 1, 3).Value <> ws.Cells(cl.Row, 3).Value Then 'Check id - 1 <> id
count = ws.Cells(cl.Row, 3).Row 'Store first id location
End If
If ws.Cells(cl.Row, 19).Value <> "Home" Then 'Home = skip loop
Select Case ws.Cells(cl.Row, 19).Value 'Check value
Case "Work" 'Work -> paste to Mother Work
ws.Cells(count, 14).Value = ws.Cells(cl.Row, 8).Value 'Copy and paste
Case "Work2" 'Work2 -> paste to Father Work
ws.Cells(count, 9).Value = ws.Cells(cl.Row, 8).Value 'Copy and paste
Case "Mobile" 'Mobile -> paste to Mother Mobile
ws.Cells(count, 13).Value = ws.Cells(cl.Row, 8).Value 'Copy and paste
Case "Mobile2" 'Mobile2 -> paste to Father Mobile
ws.Cells(count, 14).Value = ws.Cells(cl.Row, 8).Value 'Copy and paste
End Select
End If
Next cl
Set myRange = myRange.Offset(0, 12)
For Each cel In myRange
If cel.Value = 1 Then
If delRng Is Nothing Then
Set delRng = cel
Else
Set delRng = Union(delRng, cel)
End If
End If
Next cel
If Not delRng Is Nothing Then delRng.EntireRow.Delete 'Delete dummy column and all rows = 1
ws.Cells(1, 20).Value = ""
End Sub
You could use an array formula with INDEX and MATCH. This example is for the Mother Work column - and I'm guessing that the actual phone number would be in the P column.
=INDEX($P:$P,MATCH($C2&N$1,$C:$C&$H:$H,0))
Make sure to hit CTRL + SHIFT + ENTER , instead of just ENTER to commit the formula - since it needs to be an array formula to work.
If you put this formula in N2, it will look for something with the ID in C2 and the text from N1 in Column C and Column H, respectively - and return the value from column P of the matching row.

Copy and paste if one cell is blank and the other is not

So data gets pasted in to column B as the code keeps running it'll do a condition check to see there's any values in column B and paste a value in to the adjacent column A. I need to make it so it does two condition checks:
If there's values in column b, but then to check if there's values in column A before pasting so it doesn't overwrite different data that's been pasted already.
For Each Cell In y.Sheets("Compiled").Range("A:B")
If Range("B:B").Value <> "" And Range("A:A").Value = "" Then
Cell.Offset(0, -1).PasteSpecial xlPasteValues
End If
Next
You were close, don't try to loop over a multiple column range:
Sub Test()
For Each Cell In y.Sheets("Compiled").Range("B:B")
If Cell.Value <> "" And Cell.Offset(0, -1).Value = "" Then
Cell.Offset(0, -1).Value = Cell.Value
End If
Next
End Sub
NOTE: You are looping through every cell in Range("B:B") which is probably unnecessary. It'd be better if you use a lastrow value, or a static range like Range("B2:B1000"). Or you could use a criteria to exit your loop like If Cell.Value = "" Then Exit For.
Here's a version of the code that implements the lastrow value that dwirony mentioned in their answer. This also throws everything in arrays, so it might go a bit faster if you have a really large dataset.
Option Explicit
Sub test()
Dim ACol As Variant
Dim BCol As Variant
Dim lastrow As Long
Dim i As Long
lastrow = Range("B:B").Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).row
BCol = Range("B1:B" & lastrow).Value
ACol = Range("A1:A" & lastrow).Value
For i = LBound(BCol) To UBound(BCol)
If IsEmpty(ACol(i, 1)) And Not IsEmpty(BCol(i, 1)) Then
ACol(i, 1) = BCol(i, 1)
End If
Next i
Range("A1:A" & lastrow).Value = ACol
End Sub

VBA code that will look for certain criteria and if it matches place data from a different column into a another one

I need help with a VBA code that will look for certain criteria and if it matches place data from a different column into a another one.
If column C says "Circum + spa" and D says "100" then the values in row F need to move over two columns to H
until column C says "Circum + spa" and D says "0" (where it will stay in column F.)
finished result will looks like a snake.
The code I have started with this process with is:
Dim l As Long
With ActiveSheet
l = .Cells(.Rows.Count, "C").End(xlUp).Row
For i = 1 To l
If .Cells(i, "C").Value2 = "CIRCUM + SPA" And
.Cells(i, "D") = "100" Then
.Cells(i + 1, "F").Value = .Cells(i + 1, "H").Value
Next
End With
But currently it just makes one row down in column F empty... I have also attempted cut/paste and an offset but all I get are error messages.
I also know that using +1 isn't going to work in final result because I need it to grab everything until the other condition is met.
I have not started on that yet, but would appreciate any advise on a Do-Until loop.
I have attached pictures of what my worksheet looks like now vs what I need it to look like after the macro runs. Also, the rows that move will not always contain 4 cells, sometimes there will be more that's why I need the do until rather than a set range.
before[1]
after (2)
Try this
Sub Demo()
Dim ws As Worksheet
Dim cel As Range, fCell As Range, lCell As Range
Dim lastRow As Long
Dim flag As Boolean
Set ws = ThisWorkbook.Sheets("Sheet4") 'change Sheet4 to your data sheet
flag = False
With ws
lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row 'last row with data in Column C
For Each cel In .Range("C2:C" & lastRow) 'loop through each cell in Column C
If UCase(cel.Value) = "CIRCUM + SPA" Then 'check if Command Name is "CIRCUM + SPA"
If cel.Offset(, 1).Value = 100 Then 'check if SP is 100
Set fCell = cel.Offset(1, 0) 'set first cell to be copied in fCell
flag = True
ElseIf cel.Offset(, 1).Value = 0 Then 'check if SP is 0
If flag Then 'move ahead only if ("CIRCUM + SPA" & 100) already found
Set lCell = cel.Offset(-1, 0) 'set last cell to be copied in lCell
Set rng = .Range(fCell, lCell).Offset(, 3) 'set range using fCell and lCell
rng.Cut rng.Offset(, 2) 'move data from Column F to Column H
flag = False
End If
End If
End If
Next cel
End With
End Sub

Resources