Merging text in two columns - excel

How to locate and merge text in two columns on my spreadsheet and delete the second one?
The first one has the title Postnr and the second one has the title Postort. I want to merge the text in these columns with two spaces between the original text.
Example:
| Postnr | Postort |
| 752 65 | Gothenburg |
Result after I run the code:
Postaddress
752 65 Gothenburg
My code to find and select Postnr
Dim rngPostnr As Range
Set rngPostnr = Range("A1:Z1").Find("Postnr")
Range(rngPostnr, rngPostnr.End(xlDown)).Select
I understand how to do it in the sheet, but I want a macro since I do this many many times a day.
I don't want to locate and mark these columns manually since my sheets have many columns.
I need a macro that locates the columns and concatenates them and removes them and make a new column with the concatenated values, preferably with the header Postaddress.

I understand you dont know where the column is located (but its in the first row).
First iteration on the first row will find you the columns, then iterate over the values per the found column numbers, build the new string and write it in column 10 (or any other column). You can add further logic per your needs, such as, when to stop iterating (when one lastRow is bigger than the other, etc...)
Here is the basic working code that you can expend later:
Sub findAndConcat()
'last column with data
lColumn = Cells(1, Columns.Count).End(xlToLeft).Column
'find Postnr and Postort columns
For i = 1 To lColumn
If Cells(1, i) = "Postnr" Then
PostnrColumn = i
'Convert from column number to column letter
PostnrColumnName = Split(Cells(, PostnrColumn).Address, "$")(1)
End If
If Cells(1, i) = "Postort" Then
PostortColumn = i
PostortColumnName = Split(Cells(, PostortColumn).Address, "$")(1)
End If
Next i
Dim PostnrValue As String
Dim PostortValue As String
Dim newString As String
'last row with data per column
PostnrLastRow = ActiveSheet.Cells(Rows.Count, PostnrColumnName).End(xlUp).Row
PostortLastRow = ActiveSheet.Cells(Rows.Count, PostortColumnName).End(xlUp).Row
'Iterating the columns rows and building the new concatinated string
For i = 2 To PostnrLastRow
PostnrValue = Cells(i, PostnrColumn).Value
PostortValue = Cells(i, PostortColumn).Value
newString = PostnrValue & " " & PostortValue
ActiveSheet.Cells(i, 10).Value = newString
Next i
End Sub
Here is the result:

If you want to do that inside the sheet, then on the formula barn you should use concatanate like the following: =CONCATENATE(A2;" ";B2)
If you want to achieve that in vba you have to use something like the following:
ActiveCell.Offset(0, 3).Value = ActiveCell.Value & " " & ActiveCell.Offset(0, 1).Value
Where activecell (Postnr) is the first cell, and the next cell (offset 0,1|Postort) is the second part you want to concatenate and the result is inserted further down into a new column.
Edit: Here is the results to understand the example given:
Edit 2: Because you question is not clear enough I will add another way. Maybe you want to "add" the second column to the first (merge the columns into one).
You can do that using vba only.
You have to do something like that:
ActiveCell.Value = ActiveCell.Value & " " & ActiveCell.Offset(0, 1).Value

I understand how to do it in the sheet, but I want to have macro that does it since I do this many many times a day.
I also understand your vba but for this to work I need to mark the cells or does it locate the postnr and postadress columns by itself. I dont want to have to locate and mark these columns myself since this is time consuming because my sheets have many many columns. Do you understand what I mean?
I need like a macro that locates the columns and concatenates them and removes them and make a new column with the concatenated values, preferably with the header Postaddress

Related

Insert Row Every Two Rows and Subtract the Difference

I have numerous excel sheets that contain rows that have paired data. Specifically, I need to subtract the first row from the one that follows (e.g., row 2-row 1; row 4-row3; etc.) and place the result into a new row below each pair. My data in each sheet appear as follows:
I am not new to programming languages, but I am new to visual basic.
My current code is:
Sub test() Dim rng As Range
Columns(1).Insert
With Range("b2", Range("b" & Rows.Count).End(xlUp)).Offset(, -1)
.Formula = "=if(mod(row(),2)=1,1,"""")"
.Value = .Value
.SpecialCells(2, 1).EntireRow.Insert
End With
Columns(1).Delete
With Range("a1", Range("a" & Rows.Count) _
.End(xlUp)(2)).Resize(, 3)
.Columns(1).SpecialCells(4).Value = "Difference"
Union(.Columns(2).SpecialCells(4), .Columns(3) _
.SpecialCells(4)).Formula = _
"=r[-1]c-r[-2]c"
End With
End Sub
However, the result is this:
I am mainly interested in calculating the differences between row pairs in the first column shown, but it is clearly not working.
Any help would be greatly appreciated!
Easier to use formulae, rather than VBA.
Go to a second sheet in the file ("Sheet2")
Enter in A1: =Sheet1!A1-Sheet1!A2
On Sheet2, select Rows1 AND 2.
Drag down.
Then depends on what you need to do.
May be Copy | Paste Special | Values to Sheet3, and sort to remove blank rows.

Replicating values

Need a little help here.
In the "Data" Tab I want to copy values in column "c2:c1000" and paste in column "a1" of another Tab.
This is what i have so far,
Dim x As Long
Dim lastRow As Long
lastRow = Worksheet("Data").Cells(3, Columns.Count).End(xlUp).Column
For x = 1 To lastRow
If Worksheets("Sheet2").Cells(2, "A") = "" Then
Worksheets("Data").Range("c2:c1000").Copy Destination:=Worksheets("Sheet2").Range(1, "A")
Sheets("Sheet2").Range("A1").Value = Format(Now, "mm/dd/yyyy HH:mm:ss")
Else
Worksheets("Data").Range("c2:c1000").Copy Destination:=Worksheets("Sheet2").Cells(2,
Columns.Count).End(xlToLeft).Offset(, 1)
'Sheets("Sheet2").Range("A1").Value = Format(Now, "mm/dd/yyyy HH:mm:ss") --> can't figure how to increment this as this will need to be on the subsequent empty column
End If
Next
End Sub
Your help will be greatly appreciated!
Thank you.
Pasting values first into range A1 and down and then next time to cell B1 and so on, leaves no space for the timestamp to A1, B1 etc. So, I assume that you would like to paste the random values to row 2. So cells A1, B1, ... are left for the timestamp.
Inside the With statements we can refer to properties of the wsAudit so we can replace the "Worksheets("Audit")." reference with just "."
The column.count expression just checks the amount of columns in the worksheet.
The expression .Cells(2, Columns.Count) just points to last cell in the row 2.
The .End(xlToLeft).Column then looks from this column to left and is supposed to find the last not empty cell on this row. It's basically the same idea that in Excel's sheet you would go to cell XDF2 and hit CTRL+Arrow Left from keyboard.
But instead of activating the cell we just want to get the columns index number and then add 1 (the new column) and save it into variable. Now the new column is known.
The expression Range(.Cells(2, newColAudit), .Cells(1000, newColAudit)).Value is really the same as e.g. Range("B2:B1000"), but with this we can use the row and column index numbers instead. This is useful as the column number varies.
And as Samuel pointed out the copy paste operation can be avoided by setting the areas equal.
Dim wsAudit As Worksheet
Dim newColAudit As Long
Set wsAudit = Worksheets("Audit")
With wsAudit
newColAudit = .Cells(2, Columns.Count).End(xlToLeft).Column + 1
Range(.Cells(2, newColAudit), .Cells(1000, newColAudit)).Value = Worksheets("Data").Range("C2:C1000").Value
.Cells(1, newColAudit).Value = Format(Now, "mm/dd/yyyy HH:mm:ss")
End With
Much like your LastRow* variable for your source sheet, create a LastColumn variable for your destination sheet, which will find the last used column the same way you are finding your last used row.
Like so:
Dim LastColumn As Long
LastColumn = Sheets("Audit").Cells(1, Columns.Count).End(xlToLeft).Column
Then use the variable like so:
Destination:= Worksheets("Audit").Cells(1, LastColumn)
It seems that your code contradicts your question too, in your question you explained the data will be written to the Audit sheet in row 1, using the next column each time but your code looks for values in row 2 in your If statement:
If Worksheets("Audit").Cells(2, "A") = "" Then is the same as If Worksheets("Audit").Range("A2") = "" Then.
If you mean to check the first row, change the 2 to 1.
To help improve your codes efficiency:
(Also see the link to 'how to avoid select' in that question):
You can achieve 'copy/paste' without actually using the 'copy' and 'paste' methods by assigning the value of one range to the other, as example, like so:
Worksheets("Audit").Cells(1, LastColumn).Resize(999, 1) = Worksheets("Data").Range("c2:c1000").Value
Note: Change the Resize Property rows to suit the source range (in this case you are wanting to move values from C2:C1000).
*The LastRow variable is a bit confusing, as it is looking for the last used column in row 3.
If it's meant to find a column, consider renaming it to avoid confusion later on in debugging.
If it's meant to find the last row, try like this:
LastRow = Worksheet("Data").Cells(Rows.Count, 1).End(xlUp).Row

Best way to run macro for over 500K rows?

I have a file with a bunch of rows that contains data for certain part numbers from different configurations. Some of these part numbers are repeated throughout the file, and in those duplicated part numbers may contain certain data and some may not. I am trying to find the best way to determine the commonalities in the file for certain data. So for the commonalities, if one row has a value and another row is blank, the value for the nonblank row would be put into the blank row. And if the data on those two rows were different it would change the font color on the cell indicating that this part number two different unique values and should be checked.
Dim i, j, n As Long
Dim lr As Long
Dim moaf As Workbook
Dim sht As Worksheet
Application.ScreenUpdating = False
Set moaf = Workbooks("MOAF3.xlsb")
Set sht = moaf.Worksheets("Wire Data")
n = InputBox("What column # are you trying to fill in?: ")
lr = Cells(Rows.count, 2).End(xlUp).Row
For i = 2 To lr
lkup = Cells(i, 2).Value 'sets first lookup value
Fill = Cells(i, n).Value 'sets the first data value to compare
If Len(Fill) > 0 Then
For j = 2 To lr
lkup2 = Cells(j, 2).Value 'sets the second lookup value
Fill2 = Cells(j, n).Value 'sets the second value to compare
If lkup2 = lkup Then 'checks to see if p/ns are same
If Len(Fill2) = 0 Then 'checks to see if second value is blank
Cells(j, n).Value = Fill 'if value is blank the cell takes value of non blank cell
ElseIf Fill <> Fill2 Then 'checks to see if the values are non matching and non zero
Cells(i, n).Font.ColorIndex = 3 'changes font color of two cells
Cells(j, n).Font.ColorIndex = 3 'changes font color of two cells
End If
End If
Next j
End If
Next i
Application.ScreenUpdating = True
End Sub
Doing this generally freezes my excel, where my computer has 32GB of RAM and is Windows10. Is there a better approach for my problem, or is it something that can be done without using a vba? I've done some research on a method without using vba, but with like sumifs, countifs but haven't really done any deep dives.
So, if I understand your question correctly, you start with following data:
ID Column_header
2 a
3 _BLANK_
4 _BLANK_
5 b
6 _BLANK_
And you want to turn this into:
ID Column_header
2 a
3 a
4 a
5 b
6 b
I know a very simple trick for that (I have put everything in column 'A' for explanation):
Select every cell inside that column
Goto (Ctrl+G) Special, Blanks
In the formula bar, type =A2 (you are currently located in 'A3', and you want to copy there the value of the cell just above it)
Press Ctrl+ENTER
You'll see that 'A2' gets copied into 'A3', 'A3' into 'A4' and 'A5' into 'A6' (the fact that this is done for all blank cells, is due to the Ctrl+ENTER).
Record this into a macro, and it will go much faster.
I already see a question popping up : "Ok, but what about the font colour I want to change?". Well, the newly filled cells are based on a formula, so the length of =FORMULATEXT() won't be zero. You use this as a basis for conditional formatting.
Good luck
The inner for loop just needs to start at i, that is:
for j = i to lr
This should roughly half the runtime.
Further performance enhencements:
Use .Value2 instead of .Value property.
Or even better, read in the entire columns into an array, work on that in VBA, then write the result back.

If a row is empty, how do I copy/paste data from the row below it to populate the empty row?

I have a spreadsheet with numerous blank rows, and I need to extract specific data from cells below each blank row to populate the blank one. I'm just not good enough yet at VBA to figure out how to do this complex set of steps, so thank you in advance, and sorry to the developers who don't like how to do this questions.
I've broken down the steps I need.
Determine if row is empty.
If true, copy text from column A of the row below the empty row.
Paste text into column A of the empty row.
Change last three digits of text to "XXX".
Continue until end of spreadsheet.
EDIT: Cells as they currently are:
What I want them to look like:
I'm trying to do this for every set, but there may be 2, 3, 4, or more groups of rows with a blank row above them. So the VBA needs to include all of the rows in that group.
This sounds like what you want. If your numbers are numeric you'll want to convert them to text before your try to take out digits.
Sub dostuff()
For ir = 1 To 10000
If (Cells(ir, 1).value = "" And Cells(ir + 1, 1).value = "") Then _
Exit For
If (Cells(ir, 1).value = "") Then _
Cells(ir, 1).value = _
Mid(Format(Cells(ir + 1, 1).value,"00000000"),1,5) & "XXX"
Next ir
End Sub

Delete specific rows in Excel sheet

I have a table with multiple columns. I would like to delete specific rows within the table. The logic to delete is the following:
If in column B one cell contains a specific value, let's stick to "example" for this case, I would like to delete the following two rows after the row(s) which matched the criteria.
It is important to note that the criteria might appear several times within the table and that the table might have different lengths.
My idea was the following:
1. Identify all rows which contain "example" in column B
2. Store the row numbers in a variable
3. Go through the variable and create a new one which has twice the length of the first one and write the two following rows into the 2nd variable
4. Use the 2nd variable to delete the rows with that numbers.
Unfortunately, I am totally new to VBA and was not able to code it. I also tried to copy code together but I couldn't find a solution for my specific topic.
This is a very slight mod to your approach
starting from the bottom of column B, work upwards.
if we encounter "example", delete the two rows below
So if row#7 contains "example", delete row#7 and row#8
Before:
The code:
Sub RowKiller()
Dim N As Long, i As Long, t As String
t = "example"
N = Cells(Rows.Count, "B").End(xlUp).Row
For i = N To 1 Step -1
If Cells(i, "B") = t Then
Range(Cells(i + 1, "B"), Cells(i + 2, "B")).EntireRow.Delete
End If
Next i
End Sub
and after:
I think, instead, the best way to handle this is:
Loop through all of the populated rows from the last to the first. (this insures we don't pull the rug out from under us when deleting rows).
If "Example" is found in column B of that row, delete the two rows after it (we've already traversed those rows so deleting shouldn't be any big deal
Thats it.
Sub deleteRows()
Dim lastRow as Long
'get the last row
lastRow = Sheet1.Range("B" & Sheet1.Rows.Count).End(xlUp).Row
'Now work backwards
Dim i As Long
For i = lastRow to 1 Step -1 'change that 1 to whatever your first row is
If Sheet1.Cells(i, 2).value = "Example" Then
Sheet1.Rows(i + 1 & ":" & i + 2).Delete
End If
Next i
End Sub
I haven't tested that, but it looks right. You may have to tweak some things in there, but it will definitely get you in the ballpark.

Resources