Clear content of cell A2 if A2 value same with A1 - vba

I have lists of different value in column A and B which contents same value for several rows respectively. like the following:
BEFORE
column A | column B
1. a b
2. a b
3. a b
4. a b
5. z z
6. z z
7. z z
8. z z
AFTER
column A | column B
1. a b
2.
3.
4.
5. z z
6.
7.
8.
How do I delete the duplicate cell with former rows cell in same column? Like the After.
I have done the following so far:
Sub clear()
Dim x
Dim c
x = 1
c = Range("a1").Value
Do Until Cells(x, 1) = ""
If Cells(x, 1) = Cells(x + 1, 1) Then
Cells(x + 1, 1) = Range().ClearContents
End If
Loop
End Sub

Try this:
Option Explicit
Sub clear()
Dim cRow As Long
Dim CellValue As String
cRow = 2 ' start the loop in row 2
CellValue = Range("a1").Value
Do Until Cells(cRow, 1) = ""
If Cells(cRow, 1) = CellValue Then
Cells(cRow, 1).ClearContents
Cells(cRow, 2).ClearContents ' clear column B cell
Else
CellValue = Cells(cRow, 1) ' when the cell value changes,
End If
cRow = cRow + 1 ' increment the row number so the next loop goes to the next row
Loop
End Sub
I prefer variables with descriptive names over x and c.
Some issues with your code were:
Range must have a parameter, but you don't need Range when you already have the cell object with Cells()
you did not increment the variable that sets the row
the cleared cell became the new current cell and since it had just been cleared, the loop would end
you never used the c variable, but it is useful to keep a record of the comparison string.

you may want to consider the following "array" approach should speed be an issue:
Option Explicit
Sub main()
Dim i As Long, j As Long
Dim myArr As Variant, refVal As Variant
With Worksheets("MySheet") '<--| change "MySheet" with your actual sheet name
With Intersect(.UsedRange, .Columns("A:B")) '<--| consider only columns A and B rows down to the worksheet used range last one
myArr = .Value ''<--| store values in array
For j = LBound(myArr, 2) To UBound(myArr, 2) '<--| loop through array columns
refVal = myArr(1, j) '<--| get column fiurst reference value
For i = LBound(myArr, 1) + 1 To UBound(myArr, 1) '<--| loop through form current column 2nd row downwards
If myArr(i, j) = refVal Then '<--| if there's a duplicate...
myArr(i, j) = "" '<--| ...erase it
Else '<--| otherwise...
refVal = myArr(i, j) '<--| ... get the new non duplicate value as the reference one
End If
Next i
Next j
.Value = myArr '<--| write back array to worksheet
End With
End With
End Sub
using Option Explicit statement is a safe habit that at the cost of some little extra work to declare all variables pays you back with much more control over your code and much less issues in debugging and maintaining it
using full range reference (like Worksheets("MySheet").Range(...)) is a good habit to avoid issues due to user sheet jumping selections

To complement the answers from teylyn and user3598756, you could work from bottom to top to check the values:
Public Sub myClear(Optional ByRef wks As Worksheet = Nothing)
Dim c As Range
Dim col As Long
If wks Is Nothing Then Set wks = ActiveSheet
For col = 1 To 2 'Columns A and B
Set c = wks.Cells(wks.Rows.Count, col).Rows.End(xlUp)
Do While c.Row > 1
If c.Value = c.Offset(-1, 0).Value Then c.ClearContents
Set c = c.Offset(-1, 0)
Loop
Next col
End Sub
The sub will work by default on the ActiveSheet, but you can give in parameter the actual sheet you want to work on.

Related

Excel: Transposing large column with ~45,000 cells to rows with from 1-8 ID-tied

First post here so bear with me. It's possible something similar to what I am going to ask has been posted but my technical illiteracy might have prevented me from finding it.
I have a column of data ~45,000 cells.
Within these cells lie descending data of individuals identified by an ID#, followed by anywhere from 1-8 additional cells with criteria relevant to the preceding ID#.
What I'm trying to do it convert this large column to a row for each of the ~5,500 IDs.
Here is an example of what I'm trying to achieve
I come from a beginner level SAS background and have only used Excel previously in a very brief manner, and have been trying to figure this out off and on for a week or two now. I've started transposing them manually but that is going to take forever and I hope there's an easier way.
My best guess would be, from what I've seen so far, that a VBA code could be written, but I don't know where to start with that. I'm also open to any other ideas on how to achieve the result I'm trying to get.
Thanks in advance!
Sub TransposeData()
Dim Data, TData
Dim x As Long, x1 As Long, y As Long
With Worksheets("Sheet1")
Data = .Range("A1", .Range("A" & .Rows.Count).End(xlUp))
End With
ReDim TData(1 To UBound(Data, 1), 1 To 8)
For x = 1 To UBound(Data, 1)
'If the Data macthes the ID pattern (7 Digits) then
'increment the TData Row Counter
If Data(x, 1) Like "#######" Then
x1 = x1 + 1
y = 0
End If
'Increment the TData Column Counter
y = y + 1
TData(x1, y) = Data(x, 1)
Next
With Worksheets("Sheet2")
With .Range("A" & .Rows.Count).End(xlUp)
If .Value = "" Then 'If there is no data, start on row 1
.Resize(x1, 8).Value = TData 'Resize the range to fit the used elements in TData
Else ' Start on the next empty row
.Offset(1).Resize(x1, 8).Value = TData
End If
End With
End With
End Sub
If I correctly understand your problem the following code should solve it;
Sub ColToRow()
Dim inCol As Range
Set inCol = Application.InputBox(Prompt:="Please Select Range", Title:="Range Select", Type:=8) 'Get the input column as a range
Dim outCol As Range
Set outCol = inCol.Offset(0, 2) 'Set the output column as a range
Dim index As Long 'Current row
Dim cell As Range 'Current cell
Dim lastRow As Long 'The last row
Dim currRow As Long 'Current output row
Dim currCol As Long 'Current output column
lastRow = inCol.SpecialCells(xlCellTypeLastCell).Row
currRow = inCol.Row - 1
currCol = 0
For index = inCol.Row To lastRow
Set cell = ActiveSheet.Cells(index, inCol.Column) 'Set the cell range to the current cell
If Application.WorksheetFunction.IsNumber(cell) And Len(cell.Value) = 7 Then 'If numeric then we assume it is the ID, else we assume it is the
currRow = currRow + 1 'Advance to next output row
currCol = 0 'Reset column offset
cell.Copy Destination:=ActiveSheet.Cells(currRow, outCol.Column + currCol) 'Copy ID
ElseIf currRow > 0 Then 'Ensure we are within the row bounds and not at 0 or below
currCol = currCol + 1 'Advance the column
cell.Copy Destination:=ActiveSheet.Cells(currRow, outCol.Column + currCol) 'Copy Text Values until we get the next numeric value
End If
Next index 'Advance the row
End Sub
The code simply goes (in order) down the column and does the following;
- If the cell has a numeric value then we assume it is the ID and create a new row.
- If the cell has a text value we just add it to the next column in the current row, it'll continue to do this with however many string values until a new ID is reached.
Hope it helps.
-Regards
Mark
Another possible solution, based on ID being 7 digits numbers and all other numbers being not
Option Explicit
Sub main()
Dim area As Range
Dim iArea As Long
With ThisWorkbook.Worksheets("Transpose") '<--| reference relevant worksheet (change "Transpose" to your actual sheet name)
With .Range("A1", .Cells(.Rows.COUNT, 1).End(xlUp).Offset(1))
.Cells(.Rows.COUNT, 1).Value = 1111111 '<--| add a "dummy" ID to end data
.AutoFilter Field:=1, Criteria1:=">=1000000", Operator:=xlAnd, Criteria2:="<=9999999" '<--| filter its "JobCol_Master" named range on textbox ID
.Cells(.Rows.COUNT, 1).ClearContents '<--| remove "dummy" ID
With .SpecialCells(xlCellTypeVisible)
.Parent.AutoFilterMode = False
For iArea = 1 To .Areas.COUNT - 1
Set area = .Parent.Range(.Areas(iArea), .Areas(iArea + 1).Offset(-1))
.Parent.Cells(.Parent.Cells.Rows.COUNT, 3).End(xlUp).Offset(1).Resize(, area.Rows.COUNT).Value = Application.Transpose(area.Value)
Next iArea
End With
End With
End With
End Sub

Loop - Match values in two columns in different worksheets, copy entire row to new worksheet if match

I'm new in VBA coding, and would really appreciate some help solving this problem.
I need to do as follows:
Compare every value in column G, Worksheet1, to the Unique values in column D, Worksheet2.
If a value matches, copy from that row values in column: C, G & I
Paste every match into Worksheet3
I've tried this so far:
Sub test()
Application.ScreenUpdating = False
Dim rng1 As Range, rng2 As Range, rngName As Range, i As Integer, j As Integer
For i = 1 To Sheets("Worksheet1").Range("G" & Rows.Count).End(xlUp).Row
Set rng1 = Sheets("Worksheet1").Range("G" & i)
For j = 1 To Sheets("Worksheet2").Range("D" & Rows.Count).End(xlUp).Row
Set rng2 = Sheets("Worksheet2").Range("D" & j)
Set rngName = Sheets("Worksheet1").Range("H" & j)
If rng1.Value = rng2.Value Then
rngName.Copy Destination:=Worksheets("Worksheet3").Range("B" & i)
End If
Set rng2 = Nothing
Next j
Set rng1 = Nothing
Next i
End Sub
But it doesn't work.
There is a problem with this statement:
Set rngName = Sheets("Worksheet1").Range("H" & j)
The variable j refers to a row in Worksheet2, but you use it on Worksheet1. Depending on what you intended here, you should either change the worksheet name or use the variable i instead of j.
Assuming it is the first, the code could also be written as:
Dim rng1 As Range, rng2 As Range
' Iterate over the used cells in the G column of Worksheet1
For Each rng1 In Sheets(1).UsedRange.Columns(8 - Sheets(1).UsedRange.Column).Cells
' Iterate over the used cells in the D column of Worksheet2
For Each rng2 In Sheets(2).UsedRange.Columns(5 - Sheets(2).UsedRange.Column).Cells
If rng1.Value = rng2.Value Then
' Copy value from the C column in Worksheet2 to the B column in Worksheet3
Sheets(3).Cells(rng2.Row, 2).Value = rng2.Offset(0, -1).Value
End If
Next
Next
Alternative to VBA code
Instead of using code, you could do this with formulas.
For instance in Worksheet3 you could put this formula in B1:
=INDEX(Worksheet2!$C:$C, MATCH(Worksheet1!$G1,Worksheet2!$D:$D, 0))
Here is an explanation of the two main parts of that formula:
MATCH(Worksheet1!$G1, Worksheet2!$D:$D, 0)
This part will take the value from Worksheet1!$G1, find it in Worksheet2!$D:$D (i.e. the complete D column) and return the row number where it was found. The last argument (0) makes sure that only exact matches count.
INDEX(Worksheet2!$C:$C, ...)
The row number returned by MATCH will be used to get a value from the C column of Worksheet2, at that same row.
You can change that $C:$C by $H:$H to get the value from the H column, etc.
Drag/copy the formula downwards to repeat it for other rows.
I would use the Cells property and a Do loop to loop through G on WS1. Try something like this:
Dim i as Integer, j as Integer
Dim c as Range
i = 2 'Will be used to loop through WS1, Column G
j = 1 'Will be used to find next empty row in WS3
Do Until Sheets(1).Cells(i, 7).Value = ""
Set c = Sheets(2).Range("D2")
Do Until c.value = Sheets(1).Cells(i, 7).Value Or c.value = ""
Set c = c.Offset(1, 0)
Loop
If c.value = Sheets(1).Cells(i, 7).Value Then
'Find first empty row in WS3
j = 1
Do Until Sheets(3).Cells(j, 1).Value = ""
j = j + 1
Loop
'Copy row
Sheets(3).Rows(j).value = Sheets(1).Rows(I).value
End if
i = i + 1
Loop
Set c = Nothing

Excel 2013 - Filling Zeroes based on Row/Cell Value

I'm working on cleaning up timesheets for an Access database, and I'm having issues with cleaning up the data.
I have a time sheet with names in the first column, then all of the columns after that, from C to M (or so) have hours. What I am trying to accomplish is that when the Macro finds a name in the first column, it selects the columns in that row, finds the cells without hours, and fills them with zeroes
Dim r As Integer
Dim c As Range
For r = 2 To 15 Step 1
If Cells(r, 1).Value <> "" Then
Range(Cells(r, 3), Cells(r, 10)).Select
End If
Next
For Each c In Selection
If IsEmpty(c) Then
c.Value = 0
End If
Next
I'm attempting to loop and fill rows with zeroes based on the cell having a named entered in it. The problem that I'm running into is that cells are only being filled in the last name/row in the spreadsheet. The macro seems to be skipping over all but the last row.
I'm just learning VBA, so maybe I'm just missing something in the syntax.
Thanks for the help!
The problem is that you are moving on to the next selection, all the way to the last row, before you start filling in your 0s. Try this modification to your code:
Dim r As Integer
Dim c As Range
For r = 2 To 15 Step 1
If Cells(r, 1).Value <> "" Then
Range(Cells(r, 3), Cells(r, 10)).Select
End If
For Each c In Selection
If IsEmpty(c) Then
c.Value = 0
End If
Next c
Next r
Using this method, you fill in the 0s before moving on to the next selection/row.
Note: I avoid the use of .select/Selection because of the problems it can cause, so I am not sure if you will receive an error message if a row does not contain a name. If you wish to avoid this potential error, try the below:
Dim r As Integer
Dim c As Range
Dim c2 As Range
For r = 2 To 15 Step 1
If Cells(r, 1).Value <> "" Then
Set c2 = Range(Cells(r, 3), Cells(r, 10))
End If
For Each c In c2
If IsEmpty(c) Then
c.Value = 0
End If
Next c
Next r
By the way, did you strip out the Workbook and Sheet names from Range(Cells(r, 3), Cells(r, 10)) to simplify your post? I was surprised you were able to use that without errors. If so, you'd obviously have to put them back in for my code to work.
possibly,
Sub Button1_Click()
Dim Rws As Long, Rng As Range
Rws = Cells(Rows.Count, "A").End(xlUp).Row
Set Rng = Range(Cells(2, 1), Cells(Rws, 1)).SpecialCells(xlCellTypeConstants)
Rng = 0
End Sub
You want to take all of the blank cells and turn them into zeroes.
Sub zeroed_hours()
Dim rw As Long
With Sheets("Sheet1") '<-set this worksheet reference properly!
For rw = 2 To .Cells(Rows.Count, 1).End(xlUp).Row
If CBool(Len(.Cells(rw, 1))) Then 'found a name!
'C:M on this row
.Cells(rw, 3).Resize(1, 11).Replace what:="", replacement:=0, lookat:=xlWhole
End If
Next rw
End With
End Sub
This loops through the cells in column A. If it finds a value (something with length greater than zero) then it replaces all blank cells in C:M on that row with zeroes.

Autonumbering based on other column

I get a file I want to process via a macro in excel.
Column A holds values from 1-10
Column C holds a value in C1
For each value 6 in column A, the corresponding cell in Column C in the same row should be updated with a sequentially incremented value starting from the value in C1.
I had something like below, but that gave many issues, but it shows the concept I am looking for.
Sub customernumberext()
Dim a As Range, i As Long
Range("C1").Select
If ActiveCell.Value <> Empty Then
i = "C1"
For Each a In ActiveSheet.Range("a:a") where a.value = "6"
row c = i
i = i + 1
Next a
Else: MsgBox ("no number present")
End If
End Sub
If I am reading your description and errant code correctly, this should solve the problem.
Sub incr_C()
Dim rw As Long, lr As Long
With ActiveSheet
lr = .Cells(Rows.Count, 1).End(xlUp).Row
For rw = 2 To lr
If .Cells(rw, 1).Value = 6 Then
.Cells(rw, 3) = Application.Max(Range("C1:C" & rw - 1)) + 1
End If
Next rw
End With
End Sub

excel macro: for each cell with a value in a row, insert a row below with that value

I have a worksheet with ~700 rows, and 7 columns. I need each row to have just one entry. I.e. if row 1 has cell values in column A,B and C, then two new rows should be created so row 1 has one value in column A, row 2 has one value in column B and row 3 has one value in column C.
I have spent a couple hours on this (sadly) but I'm so bad, I'm not getting anywhere:
Sub TThis()
Dim rng As Range
Dim row As Range
Dim cell As Range
'just testing with a basic range
Set rng = Range("A1:C2")
For Each row In rng.Rows
For Each cell In row.Cells
If cell.Value <> "" Then
'write to adjacent cell
Set nextcell = cell.Offset(1, 0)
nextcell.Value = cell.Value
nextcell.EntireRow.Insert
End If
Next cell
Next row
End Sub
My issue is that this code deletes the row beneath it (which is not suppose to happen)
and it inserts two rows instead of one.
Thanks a ton!
I'd read your data into an array, delete the data on the worksheet, and then write back to the worksheet in a single column (whilst checking for blanks)
Example:
Sub OneColumnData()
Dim rng As Range, ids As Range, arr() As Variant, rw As Integer, col As Integer, counter As Integer
Set rng = Range("A1:C5")
Set ID = Range("G1:G5")
arr = rng.Value
counter = 1
rng.ClearContents
For rw = 1 To UBound(arr, 1)
For col = 1 To UBound(arr, 2)
If arr(rw, col) <> vbNullString Then
Range("A" & counter) = arr(rw, col)
Range("B" & counter) = ID(rw)
counter = counter + 1
End If
Next col
Next rw
End Sub