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.
Related
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
I'm trying to write a code to solve this little issue that I have, but can't seem to get it. I have multiple columns in an excel spreadsheet and in one of those columns, there are duplicate values. What I want to do is to remove the second/duplicate value but also take the integer value in one of the other columns and add it to the row where the first value is and after that delete that "second" row. I tried with the .RemoveDuplicates command, but it just deleted the duplicate value and shifted the whole column up, so I can't add the values as I wanted.
Here's an example
I only need the duplicates removed from one of the columns, D, here we see that row 5 and 10 are similar in that column and what I want to do, is to add the numbers from column C in row 5 and delete row t´10, so I'll end up with this
I really hope any of you can help as I'm a bit lost. Thanks!
Without code, you could use the advanced copy to copy unique values into another range, sumif to get your total and index/match to bring in the other columns. Once you get that figured out, record it as a macro and clean it up.
Resume your data with Pivot Tables.
Your inputdata looks like this:
You could resume your data using Pivot Tables, and group the data by that 4th column and sum values in 3rd column. Something like this:
This way you could create a new datarange, where you have grouped your data as you wish, excluding innecesary rows. Try it!
Work from the bottom up if you are going to delete rows. See if there is a match to the value in column D above the row you are working on. If there is a match, sum the values in column C into the matched row and remove the row you're working on.
Sub words()
Dim i As Long, m As Variant
With Worksheets("sheet1")
For i = .Cells(.Rows.Count, "D").End(xlUp).Row To 2 Step -1
m = Application.Match(.Cells(i, "D").Value, .Range("D:D").Resize(i - 1, 1), 0)
If Not IsError(m) Then
.Cells(m, "C") = .Cells(m, "C").Value2 + .Cells(i, "C").Value2
.Cells(i, "D").EntireRow.Delete
End If
Next i
End With
End Sub
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
I have 3 columns in Excel 2010 with email addresses, I need to be able to narrow all 3 columns to only have unique values. I don't necessarily need to merge the remaining values into a single column, but I definitely need to eliminate duplicates. I found another post that had a VB with it, but it didn't seem to work. It removed only a few duplicates:
Sub removeDuplicates()
Dim lastCol As Integer
lastCol = 5 'col 5 is column E
Dim wks As Worksheet
Set wks = Worksheets("Sheet1")
Dim searchRange As Range
Set searchRange = wks.Range("A1:A" & wks.Cells(Rows.Count, "A").End(xlUp).Row)
Dim compareArray As Variant
Dim searchArray As Variant
'Get all values from Col A to search against
compareArray = searchRange.Value
For col = lastCol - 1 To 1 Step -1
'Set values to search for matches
searchArray = searchRange.Offset(0, col - 1).Value
'Set values to last column to compare against
compareArray = searchRange.Offset(0, col).Value
For i = 1 To UBound(compareArray)
If compareArray(i, 1) = searchArray(i, 1) Then
'Match found, delete and shift left
Cells(i, col).Delete Shift:=xlToLeft
End If
Next i
Next col
End Sub
Thanks!
Here is how I would propose doing this if it is a one-off task that you don't have to do very often.
Rather than typing out the entire process in detail, I have done a screencast of how I did this (and the entire process barely took me a minute to do).
The quick overview:
You will need to add a few temporary helper columns for unique values from each email list (one for each list), a 'merged list' column and then a final column. Filter for the unique emails using the 'Advanced' filter option one column at a time. Paste those values into the temporary column for that email list and then clear the filter. Repeat until you have gone through each column and each temporary column has the unique values in it from each list. Once you have the uniques from each list, paste these one at a time into the 'merged list' column (stacking the results in one long list) and then do a unique filter on that. Copy/paste the uniques from that list into your final column, clear the filter, and you're done.
Screencast is below:
http://screencast.com/t/zL8VmUut
Cheers!
Since the first column are the ones you already contacted, swap the first column with the second and on the 3rd write a YES or NO value if email was found on the second column (the ones you already contacted).
Formula.
=IF(ISERROR(VLOOKUP(A2,$B$2:$B$11,1,FALSE)),"Not Contacted","Yes")
As you can see, the one with Yes status is on the contacted list, you just filter the Not Contacted and you will have a new pending list in column A.
Simple.
So I have this file with 60K rows. My data analyst people need to go through this and pick out about 30K rows. This occurs every few days.
They have 1 sheet with the 60K rows, and they have another with the 30k rows to pull out. I put them together in one workbook. then what I did was write a macro that took all the values in the column they are using for finding the correct rows (It's column A, an ID column) and put those values in an array.
code:
'in this code the active sheet is the one with the 30k rows to pull
For i = 1 To numrows
killArray(index) = ActiveCell.Offset(i - 1, 0).value2 'did research and value2 is fastest
index = index + 1
Next
and then I used the autofilter:
'here the sheet with all 60k rows is active
Cells(1, IdCol).entireColumn.autofilter Field:=1, Criteria1:=Array(killArray), Operator:=xlFilterValues
So that then takes all 30k Id's puts them into an array, and filters the sheet with all rows using the array. Then the data guys can briefly look over it, and delete all of those rows.
now, they have decided they really want to use a custom format for the ID column. all id's are between 1 and 6 digits. so from 1 - 999999. the data guys have decided they like formatting it so that ALL id's are 6 digits, with leading 0's. so id 1 would be 000001.
the problem is when I use .value to put the id's into the kill array, it gets the id without formatting. so id 000001 would be just 1. this would be fine except the autofilter doesnt work now. because id - 1, does not match id - 000001. I've done some checking, and I found I could use killArray(index) = ActiveCell.Offset(i - 1, 0).text but during the course of my research (and testing) I've discovered this is VERY slow.
Is there a way to have autofilter ignore the formatting? I've done lots of reseach but I have only managed to find people having issues with dates. I don't have an issue with dates
You can probably get better performance with
killArray = application.transpose(some_range.value2)
for n = lbound(killarray) to ubound(killarray)
killarray(n) = Format(killarray(n), "000000")
next n
or even
Dim killArray
Dim somerange As Range
Set somerange = Range("A2:A10000")
With somerange
killArray = Application.Transpose(Evaluate("INDEX(TEXT(" & .Address & ",""000000""),)"))
End With
If you have a need for speed, first remove the un-necessary loop:
For i = 1 To numrows
killArray(Index) = ActiveCell.Offset(i - 1, 0).Value2
Next
This can be replaced by:
killArray(Index) = ActiveCell.Offset(numrows - 1, 0).Value2