I have an Excel workbook I imported with 24,000 business names and addresses. I can't figure out how to separate them into different cells because no commas exist and the some businesses have multiple spaces in the name. Here is an example of what is in each column. Each line is in a separate row.
P & S DELI GROCERY 730 COLUMBUS AVENUE New York NY 10025
ANGELIKA FILM CENTER 18 WEST HOUSTON STREET New York NY 10012
SHASHEMENE INT'L RESTAURA 195 EAST 56 STREET New York NY 11203
CARVEL ICE CREAM 1006 EAST 233 STREET New York NY 10466
LEXLER DELI 405 LEXINGTON AVENUE New York NY 10174
SNACK TIME GRILL 87-69 LEFFERTS BOULEVARD New York NY 11418
MITCHEL LONDON FOODS 22 EAST 65 STREET New York NY 10065
SPOON BREAD CATERING 364 WEST 110 STREET New York NY 10025
TERMINAL CAFE/YANKEE CLIPPER 0 GUARDIA AIRPORT PARKING New York NY 11371
PLAZA BAGELS & DELI 73 NEW DORP PLAZA New York NY 10306
B & M HOT BAGEL & GROCERY 203 GIFFORDS LANE New York NY 10308
TEXAS ROTISSERIE 94 FULTON STREET New York NY 10038
One easy way to get going is to use the `Text to Columns function under the Data tab.
Highlight your cells that you want to split up, and click "Text to Columns". Choose a Delimiter, click "Next", then choose "Space".
Now, it'll take a word, put it in a cell, then take the next word (after a space), and put it in the cell next to that, etc.
The problem I forsee is this isn't going to be a one shot solution. As you mention, the restaurant names can be one word, of up to infinity words. Unless you see some logic in how it's spread out, I think this is your best bet.
For instance, is it safe to assume that if we are reading from left to right, and come across a number, that number starts the address and all preceding text is the restaurant name? ...I doubt it actually, what if my restaurant is called "Bruce's 21 Jump Street Eatery"? As #Johankr points out, this is probably more rare, but you should be aware of this possibility if you're just going to run the macro, save and close (without any human review). You could get a list of major cities, zip codes, etc. and use that to help parse through though and determine where the address starts/ends.
Copy it an paste into Google Spreadsheet and then use regular expressions (REGEXEXTRACT).
So for example to extract everything before the number use:
=REGEXEXTRACT(A1, "(\D*)\d")
It will extract P & S DELI GROCERY. Then to get the number use:
=REGEXEXTRACT(A1, "\D+(\d+)\D*")
It will get you 730. And so on...
This vba Should work for most of what you want:
Sub splitaddress()
Dim ws As Worksheet
Dim rng As Range
Dim oArr() As Variant
Dim lastrow As Long
Dim spltstr() As String
Dim i As Long
Dim j As Long
Dim h As Boolean
Set ws = Sheets("Sheet1")'Change to your sheet name.
lastrow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
ReDim oArr(1 To lastrow, 1 To 5)
j = 1
h = False
For Each rng In ws.Range("A1:A" & lastrow)
spltstr = Split(rng)
For i = LBound(spltstr) To UBound(spltstr)
If i = UBound(spltstr) Then
oArr(j, 5) = spltstr(i)
ElseIf i = UBound(spltstr) - 1 Then
oArr(j, 4) = spltstr(i)
ElseIf Not h And spltstr(i) = UCase(spltstr(i)) And InStr("1234567890", Left(spltstr(i), 1)) = 0 Then
oArr(j, 1) = oArr(j, 1) & spltstr(i) & " "
ElseIf InStr("1234567890", Left(spltstr(i), 1)) > 0 Or (h And spltstr(i) = UCase(spltstr(i))) Then
h = True
oArr(j, 2) = oArr(j, 2) & spltstr(i) & " "
ElseIf spltstr(i) <> UCase(spltstr(i)) Then
oArr(j, 3) = oArr(j, 3) & spltstr(i) & " "
End If
Next i
oArr(j, 1) = Trim(oArr(j, 1))
oArr(j, 2) = Trim(oArr(j, 2))
oArr(j, 3) = Trim(oArr(j, 3))
h = False
j = j + 1
Next rng
ws.Range("B1").Resize(lastrow, 5).Value = oArr
End Sub
If the street address does not start with a number it will not work.
If all the contacts only exists as a string, i.e. all data in the same cell, no solution is likely to be able to be able to split all contacts properly.
Here are some starting points though, all based on the assumption that the rest of the data looks fairly similar at least.
Very few business are likely to contain numbers in the names, so you can probably safely split address using the first occurance of a number as the divider between name and adress.
Create a lookup table for State and abbreviation. Should be possible to split the adress part of the string into two parts/lines using that.
Assumptions: The City is always = "New York"; the State is always =
"NY".
Place your data in column A starting at row 2.
In columns C thru L, at row 1, type numbers 0 to 9, where each column
gets 1 of the digits (0,1,2 ... 9).
Paste the following into cell C2:
=IF(TYPE(FIND(C$1,$A2,1))=16,LEN($A2),FIND(C$1,$A2,1))
Select and copy cell C2, select range D2:L2 and paste the copied
formula from cell B2.
Paste the following into cell B2: =MIN(C2:L2)
Paste the following into cell M2: =TRIM(MID(A2,1,B2-1))
Paste the following into cell N2: =TRIM(MID(A2,B2,FIND("New York_
NY",A2,1)-1-B2))
Type "New York" in cell O2.
Type "NY" in cell P2.
Paste the following into cell Q2: =RIGHT(A2,5)
Next select copy range B2:Q2 and paste it in rows B3 to end of your
data.
Related
I have been trying to figure out how to merge two tables from the same workbook into a third one using VBA. Example :
Worksheet1:
From To Value
Italy Japan 1000
France Japan 500
Canada Japan 0
France Italy 700
Worksheet2:
From To Value
Italy Japan 5555
France Japan 1111
Canada Japan 777
Canada France 333
Disired output (worksheet3):
From To Value1 Value2
Italy Japan 1000 5555
France Japan 500 1111
Canada Japan 0 777
France Italy 700
Canada France 333
I would need a VBA solution since the original tables are about 400 rows long, and I would need to perform the same operation for several workbooks. I would be very grateful for any suggestion regarding this problem !
Edit:
In case it is of interest to anyone, I managed to make a working code. Worksheet1 was a nickname for "List Import" and Worksheet2 is "List Export". In both sheets, I inserted a column (C) that states both countries. I used that new column and the values to build the table in Worksheet3 (now "Combolist").
Sub combolist()
Dim lastRowImp As Long, lastRowExp As Long, startPaste As Long, endPaste As Long
Dim ws As Worksheet, Lookup_Range As Range, i As Integer
Dim lastRow As Long
lastRowImp = Sheets("List Import").Cells(Rows.Count, 1).End(xlUp).Row
lastRowExp = Sheets("List Export").Cells(Rows.Count, 1).End(xlUp).Row
startPaste = lastRowImp + 1
endPaste = lastRowImp + lastRowExp - 1
'add a new sheet and headers
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = "Combolist"
Sheets("Combolist").Range("B1") = "Import"
Sheets("Combolist").Range("C1") = "Export"
Sheets("Combolist").Range("C1").EntireRow.Font.Bold = True
'copy flows from import and export list
Sheets("Combolist").Range("A1:A" & lastRowImp) = Sheets("List Import").Range("C1:C" & lastRowImp).Value
Sheets("Combolist").Range("A" & startPaste & ":A" & endPaste) = Sheets("List Export").Range("C2:C" & lastRowExp).Value
'remove duplicates
lastRow = Sheets("Combolist").Cells(Rows.Count, 1).End(xlUp).Row
Sheets("Combolist").Range(Cells(1, 1), Cells(lastRow, 1)).RemoveDuplicates Columns:=Array(1), Header:=xlYes
Set ws = ActiveWorkbook.Sheets("Combolist")
lastRow = Sheets("Combolist").Cells(Rows.Count, 1).End(xlUp).Row
'populate Import values
Set Lookup_Range = Sheets("List Import").Range("C1:D" & lastRowImp)
With ws
For i = 2 To lastRow
On Error Resume Next
If Application.WorksheetFunction.VLookup(ws.Cells(i, 1), Lookup_Range, 2, False) = "" Then
ws.Cells(i, 2) = 0
Else
ws.Cells(i, 2) = Application.WorksheetFunction.VLookup(ws.Cells(i, 1), Lookup_Range, 2, False)
End If
Next i
End With
'populate Export values
Set Lookup_Range = Sheets("List Export").Range("C1:D" & lastRowExp)
With ws
For i = 2 To lastRow
On Error Resume Next
If Application.WorksheetFunction.VLookup(ws.Cells(i, 1), Lookup_Range, 2, False) = "" Then
ws.Cells(i, 3) = 0
Else
ws.Cells(i, 3) = Application.WorksheetFunction.VLookup(ws.Cells(i, 1), Lookup_Range, 2, False)
End If
Next i
End With
End Sub
While this could be solved with VBA, you're likely to be better off using formulas (unless you must do this very frequently). The VBA solution will require some know-how, and even more if you want to be able to maintain the solution.
An Excel formula would be quite simple. First, create a UniqueID column:
UniqueID From To Value
Italy_Japan Italy Japan 1000
France_Japan France Japan 500
Canada_Japan Canada Japan 0
France_Italy France Italy 700
Canada_France Canada France
You would do the same thing for both tables. Next, get all of the unique UniqueID's. For this, you could use Data > Remove Duplicates, just be sure to make a copy before removing duplicates, otherwise you are removing records from your source. Put this list of UniqueID's into a new Table. Keep in mind that all of this will be easier if all of your data is in Table format (you'll see a Table tab in the ribbon when inside of the table range.
If you need to format your data as a table, go to the worksheet, press CTRL+HOME (this goes to the very first cell). If your first cell is in another location, just navigate there instead. If your table is the only data on the worksheet, try using CTRL+SHIFT+END from here to highlight to the last used cell. Otherwise, a combination of CTRL+SHIFT+RIGHT and CTRL+SHIFT+DOWN will get you what you need. Finally, name your table for the love of all that is excel, this one simple habit saves a ton of time. For my example I will assume that you have a Primary and Secondary table.
Our formula in our combined table would then look something like this:
=IfError(Vlookup([UniqueID], Primary, Column(Primary[Value]), False), "")
Or, if your Primary table doesn't start in the first column, use this:
=IfError(Vlookup([UniqueID], Primary, 4, False), "")
The difference here is that the former will change the index as the column is moved, the latter will not, and must be edited if the table is edited.
Do the same thing in your next column for the other table:
=IfError(Vlookup([UniqueID], Secondary, Column(Primary[Value]), False), "")
=IfError(Vlookup([UniqueID], Secondary, 4, False), "")
This will 'merge' the two sets based on the shared UniqueID and will leave blanks if the record doesn't exist. Learning how to do this may be less convenient than the learning how to do it in VBA, but I would strongly dissuade you from trying to learn VBA if you can't use an implementation like this.
To be clear, the reason why the formula approach is ideal in this instance is that the task you are asking for help with is very simple, and you would be better developing your Excel skills since, doing so, will allow you to solve similar tasks much faster in the future. Even a novice could implement this solution within 15 minutes or so, where it would easily take you days to learn a scalable VBA solution.
I'm a bit of an Excel noob so bear with me here. I have the following abridged sheet:
Sheet1
H AP AO
1 Transaction Description Employee Name Type
2 ER 12345678 blank blank
3 ER 13182984 blank blank
4 ER 18213289 blank blank
5 ER 13829429 blank blank
6 ER 89234024 blank blank
And another sheet in the same file to reference the names against:
Sheet2
E I
1 Expense Report Number Employee Name
2 12345678 Chris Rock
3 13182984 Hank Hill
4 18213289 Tom Sawyer
5 13829429 Elon Musk
6 89234024 Tupac Shakur
And I was wondering how to efficiently fill in the first excel sheet's Employee Name and Type columns from the matching report number of the second sheet as such:
Sheet1
H AP AO
1 Transaction Description Employee Name Type
2 ER 12345678 Chris Rock A
3 ER 13182984 Hank Hill A
4 ER 18213289 Tom Sawyer A
5 ER 13829429 Elon Musk A
6 ER 89234024 Tupac Shakur A
My attempt so far:
Set RE = CreateObject("vbscript.regexp")
RE.pattern = "(\d{8})"
Set allMatches = RE.Execute(ActiveSheet.Region ("H:H") #extract the 8 numbers
#somehow extract the 8 numbers to reference against the second sheet
With .Columns(AP)
.Resize(.Rows.Count - 1).Offset(1).SpecialCells(xlCellTypeVisible).Formula = "=IF(ISERROR(VLOOKUP(reference number,EEM BI + mapping!I:I,2,0)),""Check employee ID"",VLOOKUP(reference number,EEM BI + mapping!I:I,2,0))"
As you can see I'm pretty lost in this code.. Any help is much appreciated
try this test code
Sub Test()
Dim ddd As Variant ' convert sheet1.columnH into an array
ddd = Sheets("Sheet1").Range("h2:h6").Value ' 2D array 1 x N
ddd = Application.Transpose(ddd) ' 2D array N x 1
ddd = Application.Transpose(ddd) ' this changes to 1D array
Dim i As Integer
For i = 0 To UBound(ddd) ' remove the "ER" from each member of the array
ddd(i) = Split(ddd(i))(1)
Next i
Dim findMe As String
Dim rng As Range
For Each rng In Sheets("Sheet2").Range("e2:e6")
findMe = rng.Value
For i = 1 To UBound(ddd)
If StrComp(findMe, ddd(i), vbTextCompare) = 0 Then
Sheets("Sheet1").Range("ap1").Offset(i) = rng.Offset(0, 4).Value
Sheets("Sheet1").Range("ao1").Offset(i) = "A"
End If
Next i
Next rng
End Sub
In your table in Sheet1 if the 8 digit number always starts at position 4, as you show, you can use the MID function seen in the formula below. If not, we would merely have to change MID to something a bit more complex, depending on the real data. No need for REGEX unless the text analysis is complex.
Given the order of Employee Name and Expense Report Number in your lookup table, INDEX(MATCH(... would be one solution.
Although you could use LOOKUP, it may be more efficient to use INDEX(MATCH.... LOOKUP, among other things, to work properly, requires that your lookup table be sorted. That is not necessary with INDEX/MATCH.
Something like
=INDEX(EmployeeName,MATCH(--MID(H2,4,8),ExpenseReportNumber,0))
For efficiency, the references to the two columns (EmployeeName and ExpenseReportNumber) should be as short as possible. Whole column references (eg: $E:$E and $I:$I will work, but will take longer to execute.
Here is the problem I am trying to solve.
First I need to run an SQL query. This query returns data that has up to 12 categories, each dependent on the previous. For example, if my input into the query was 'United States', then column 1 would be 'United States', and column 2 would have each of the 50 states. Column three would then have all the major cities. So we end up with about 1000 rows, each with 'United States' on the left, a state in the middle, and the city that the state is on in the third column, like this:
United States Texas Austin
United States Utah Salt Lake City
United States Nevada Las Vegas
What I need to do is to programmatically create data validation for each of the categories based on the previous columns value.
My current idea is to take the original data, split it out into different sheets two columns at a time, and remove the duplicates. Then I would take the unique values from column A and paste them across the top, and distribute the data from column B into the correct columns. Then I'd make that a table, and make my data validation look at the headers in the table.
The problem comes in here: I don't know how to quickly distribute the data from column B into the correct column.
For clarity, this is what my data looks like on every page, except with thousands of pairs in columns A and B, and I need to distribute it into the three columns quickly.
Texas Utah Nevada
Texas Austin
Utah Salt Lake City
Nevada Las Vegas
Here's what I'm working with so far:
Num = 1
Col = 6
EndRow = Columns(Col).Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
For Col = 6 To 19
Set rng = Range(Cells(2, Col), Cells(EndRow, Col))
Unique = CountUnique(rng)
If Unique > 1 Then
Set rng2 = Sheets("SQL Dump").Range(Cells(2, Col), Cells(EndRow, Col + 1))
rng2.Copy
Set ws = Sheets.Add
ws.Name = "List" & Num
Num = Num + 1
ws.Activate
Cells(1, 1).PasteSpecial xlPasteAll
'MsgBox ("Do Stuff")
os.Activate
End If
Next Col
So that splits it into unique sheets as needed based on the two columns.
If anyone knows of a way to quickly sort, that would be greatly appreciated!
Or if you know a way to solve the problem more efficiently overall, I'd love to hear that, too--thanks!
EDIT: CountUnique is a function that I am using to count the number of Unique values that exist in a column.
This transposes ranges quite easily. is this what youre looking for?
Sub TransposeRangeValues()
Dim TmpArray() As Variant, FromRange As Range, ToRange As Range
Set FromRange = Sheets("Sheet1").Range("a1:c4")
Set ToRange = ThisWorkbook.Sheets("Sheet1").Range("a1")
TmpArray = Application.Transpose(FromRange.Value)
FromRange.Clear
ToRange.Resize(FromRange.Columns.Count, FromRange.Rows.Count).Value2 = TmpArray
End Sub
In column B of Sheet1 I have a list of divisions that coincide with ship dates. I need the divisions to be copied from Sheet1(columnB) to Sheet2(columnC). The divisions go from row 3 to 17 and once the macro gets to the division in row 17 I need it to start over with the division in row 3 and add to the bottom of the column. Here is what I have but it doesn't give me any output.
For i = 2 To 2
For y = 3 To 17
x = x + 1
Sheets("Sheet2").Cells(x, 3).Value = Sheets("Sheet1").Cells(y, i).Value
Next y
Next i
Input:
Atlanta
Cincinnati
Columbus
Michigan
Central
Louisville
Delta
Nashville
Mid-Atlantic
Southwest
Charleston
Indiana
Southwest
Dillon
California
Output:
Atlanta
Cincinnati
Columbus
Michigan
Central
Louisville
Delta
Nashville
Mid-Atlantic
Southwest
Charleston
Indiana
Southwest
Dillon
California
Atlanta
Cincinnati
Columbus
Michigan
Central
Louisville
Delta
Nashville
Mid-Atlantic
Southwest
Charleston
Indiana
Southwest
Dillon
California
Your Outer For Loop For i = 2 To 2 runs only once, change it to For i = 1 To 2 to run two times and n to run n times etc
x = 3
For i = 1 To 2
For y = 3 To 17
Sheets("Sheet2").Cells(x, 3).Value = Sheets("Sheet1").Cells(y, 2).Value
x = x + 1
Next y
Next i
You can do this with a single loop, might be easier if you instantiate a few range variables. As others have noted, your outer loop is beginning at "2" and ending at "2", so that is why it is not repeating as you intend.
Sub fillValues()
Dim i As Integer
Dim howManyTimes as Integer
Dim copyRange As Range
Dim pasteRange As Range
Dim rowCount as Long
howManyTimes = 2 'modify as needed; tells the procedure how many times to loop
'## Define the range to "copy"
Set copyRange = Sheets("Sheet1").Range("C3:C17")
'## Get the # of rows in this range
rowCount = copyRange.Rows.Count
'## Define the original destination to "paste":
Set pasteRange = Sheets("Sheet2").Range("A3") 'this will be modified later
'## Loop and input the values:
For i = 1 To howManyTimes
pasteRange.Offset((i - 1) * rowCount).Resize(row.Count).Value = copyRange.Value
Next
End Sub
Try:
set sht1 = ThisWorkbook.sheets("Sheet1")
set sht2 = ThisWorkbook.sheets("Sheet2")
set rng = sht1.Columns(2).UsedRange
j = 1 ' Change for where you want it to start
for each cell In rng.cells
sht2.cells(1,j) = cell
j = j + 1
next cell
You can accomplish this pretty easily without VBA. In column C of Sheet2, enter:
=INDEX($B$3:$B$17,MOD(ROW(C1)-ROW($C$1),COUNTA($B$3:$B$17))+1)
And just copy down as far as you want to go. Change $C$1 to the first row of the Sheet2 column.
OPTIONAL:
I also suggest using Named Ranges to make life easier when you come back a year later and can't remember what you were doing. So, do:
Formulas->Define Name->DivisionsList in Name field, =Sheet1!$B$3:$B$17 in Refers to: field->OK
And:
Formulas->Define Name->FirstRow in Name field, =Sheet2!$C$1 in Refers to: field->OK
Then just enter this in Column C of Sheet2 and copy down:
=INDEX(DivisionsList,MOD(ROW(C1)-ROW(FirstRow),COUNTA(DivisionsList))+1)
Change the address of FirstRow as necessary.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I am trying to match 2 columns in one worksheet with 2 (or potentially more) columns in another worksheet.
I have posted a sample of my worksheet data which hopefully gives a good description of what I have been trying to do for the past week. I think I am on the right track but I don't know how to properly reference between the two worksheets.
What I would like to do is look at Location 1 column, then see if that location references with my RefSheet in either location 1 or location 2.
If it does, I want to see if Location 2 then matches up in the somewhere in the same row on the RefSheet. If there is a match, I want to highlight the cell/cells yellow and give the ID number from RefSheet.
If there is no match I want to either highlight it red or no highlight.
Sheet All
A B C D
ID Location 1 Location 2 Given ID
1 West North
2 North South
3 South East
4 East West
5 East East
6 South West
Sheet RefSheet
A B C
ID Location 1 Location 2
1 West North
2 West East
3 South East
4 South North
What it should look like on the original Worksheet
A B C D
ID Location 1 Location 2 Given ID
1(Yellow) West North 1
2(Yellow) North South 4
3(Yellow) South East 3
4(Yellow) East West 2
5(Red) East East
6(Red) South West
Here is my terrible Code
Sub roadfinder()
Dim lngLast As Long
Dim lngCounter As Long
Dim rCell As Range
Dim lCnt As Long
Dim nextIntersection
Dim RefSheet As Worksheet
Dim list As Worksheet
Set intersections = ThisWorkbook.Sheets("RefSheet")
Set crashes = ThisWorkbook.Sheets("All")
Application.ScreenUpdating = False
lngLast = Cells(Rows.Count, "B").End(xlUp).Row
For lngCounter = 2 To lngLast
With Cells(lngCounter, "B")
For Each rCell In RefSheet.Range("B1", RefSheet.Cells(RefSheet.Rows.Count, 1)).Cells
lCnt = lCnt + 1
'I wasn't sure what to put as a reference to
If .Value = "" Then
.Interior.ColorIndex = 6
End If
Next rCell
End With
Next lngCounter
Application.ScreenUpdating = True
End Sub
Actually, it's easy enough to do by a simple excel formula without any programming.
Just put into cell 2 of your column for Given ID the following as an array formula:
=SUM(SIGN((B2=Refsheet!$B$2:$B$5)*(C2=Refsheet!$C$2:$C$5)+(B2=Refsheet!$C$2:$C$5)*(C2=Refsheet!$B$2:$B$5))*Refsheet!$A$2:$A$5)
And copy this formula through the whole column
(I assume your input locations are in columns B, C, and your RefSheet range is in A2-C5, like you provided in your example)
You'd better make named ranges on your Refsheet, though, so that formula will become:
=SUM(SIGN((B2=Ref_Loc1)*(C2=Ref_Loc2)+(B2=Ref_Loc2)*(C2=Ref_Loc1))*Ref_ID)
(Remember, it should be an array formula).
Once you have the ID you can easily make Conditional formatting of your input cells based on whether the ID is 0 (meaning not found) or not.
It is essential for refsheet location pairs to be unique,for ID to be numeric and not zero.