I try to sort a sheet in my workbook. After the macro sorted my table it should remove all duplicates based on the column A.
But every time I use the macro, I get the following error:
Sub SortAndRemoveDUBS()
Dim Rng As Range
Dim LastRow As Long
Dim i As Long
Application.ScreenUpdating = False
LastRow = Cells(Rows.Count, "B").End(xlUp).Row
Set Rng = Range("A4:P" & LastRow)
With Rng
.Sort Key1:=Range("A4"), Order1:=xlAscending, key2:=Range("P4"), order2:=xlDescending, _
Header:=xlYes, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom
End With
Dim arr() As Variant
Dim cnt As Long
cnt = 0
For i = LastRow To 2 Step -1
If WorksheetFunction.CountIf(Range(Cells(2, "A"), Cells(i, "A")), Cells(i, "A")) > 1 Then
ReDim Preserve arr(cnt)
arr(cnt) = i
cnt = cnt + 1
End If
Next i
If Len(Join(arr)) > 0 Then ActiveSheet.Range("A" & Join(arr, ",A")).EntireRow.Delete
Application.ScreenUpdating = True
End Sub
This line gets highlighted:
ActiveSheet.Range("A" & Join(arr, ",A")).EntireRow.Delete
Does someone see what the probleme is?
Use RemoveDuplicates()
and, since you remove all duplicates from column "A" either you sort on column "A" or on column "P": I assume you need this latter
Sub SortAndRemoveDUBS()
With Worksheets("MyDataSheet") '<--| change "MyDataSheet" to your actual worksheet name
With Range("A4:P" & .Cells(.Rows.Count, "B").End(xlUp).Row)
.RemoveDuplicates Columns:=Array(1)
.Sort Key1:=Range("P4"), order1:=xlDescending, _
Header:=xlYes, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom
End With
End With
End Sub
If you want to remove all duplicates except the first one then this code will work in 2007+:
Sub SortAndRemoveDUBS()
Dim Rng As Range
Dim LastRow As Long
Application.ScreenUpdating = False
LastRow = Cells(Rows.Count, "B").End(xlUp).Row
Set Rng = Range("A4:P" & LastRow)
With Rng
.Sort Key1:=Range("A4"), Order1:=xlAscending, key2:=Range("P4"), order2:=xlDescending, _
Header:=xlYes, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom
End With
Rng.RemoveDuplicates Columns:=1, Header:=xlYes
Application.ScreenUpdating = True
End Sub
Edit:
If you want to remove all duplicates this code will do the job:
Sub SortAndRemoveDUBS()
Dim Rng As Range
Dim LastRow As Long
Dim i As Long
Dim RngToDelete As Range
Application.ScreenUpdating = False
LastRow = ThisWorkbook.Worksheets("Sheet1").Cells(Rows.Count, "B").End(xlUp).Row
Set Rng = ThisWorkbook.Worksheets("Sheet1").Range("A4:P" & LastRow)
With Rng
.Sort Key1:=Range("A4"), Order1:=xlAscending, key2:=Range("P4"), order2:=xlDescending, _
Header:=xlYes, OrderCustom:=1, MatchCase:=False, _
Orientation:=xlTopToBottom
For i = LastRow To 4 Step -1
If WorksheetFunction.CountIf(.Resize(, 1), .Cells(i - 3, 1)) > 1 Then
If RngToDelete Is Nothing Then
Set RngToDelete = .Cells(i - 3, 1).EntireRow
Else
Set RngToDelete = Union(RngToDelete, .Cells(i - 3, 1).EntireRow)
End If
End If
Next i
End With
If Not RngToDelete Is Nothing Then
RngToDelete.Delete
End If
Application.ScreenUpdating = True
End Sub
Try using Application.WorksheetFunction.Match method
Example
Option Explicit
Sub Function_Match()
Dim vRow As Variant
Dim i As Long, LastRow As Long
LastRow = WorksheetFunction.CountA(Columns(1))
For i = LastRow To 2 Step -1
vRow = Application.Match(Cells(i, 1).Value, Range(Cells(1, 1), Cells(i - 1, 1)), 0)
If Not IsError(vRow) Then
Rows(vRow).Delete
End If
Next
End Sub
Related
I have this Macro which essentially uses two sheets - sheet2 updates sheet1 and then kills the second worksheet.
I noticed that when it comes to one part of the macro (delete row which has "Delete" in column A in worksheet 1) it doesn't appear to work if I run the Macro from worksheet 2. If I run it from Sheet 1 is works without a problem.
This is the full code, just in case you need to look at it - I'll highlight the part that I'm having trouble with next.:
Public Sub Cable_Load_full()
'~~> Copy New Accounts from worksheet2
Dim ws1 As Worksheet, ws2 As Worksheet
Dim bottomL As Integer
Dim x As Integer
Dim c As Range
Dim i As Long, J As Long, LastCol As Long
Dim ws1LR As Long, ws2LR As Long
Dim ws1Rng As Range, aCell As Range
Dim SearchString
Set ws1 = Sheets("CableSocials")
Set ws2 = Sheets("CableRevised")
bottomL = ws2.Range("A" & Rows.Count).End(xlUp).Row: x = 1
x = ws1.Range("A" & Rows.Count).End(xlUp).Row
x = x + 1
For Each c In ws2.Range("A1:A" & bottomL)
If c.Value = "New" Then
c.EntireRow.Copy ws1.Range("A" & x)
x = x + 1
End If
Next c
'~~> Assuming that ID is in Col B
'~~> Get last row in Col B in Sheet1
ws1LR = ws1.Range("B" & Rows.Count).End(xlUp).Row
'~~> Set the Search Range
Set ws1Rng = ws1.Range("B1:B" & ws1LR)
'~~> Adding Revise Column to worksheet 1
ws1.Columns("A:A").Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("A1").Value = "Revise"
Set ws2 = Sheets("CableRevised")
'~~> Turn off Filter
ws2.AutoFilterMode = False
'~~> Get last row in Col A in Sheet2
ws2LR = ws2.Range("B" & Rows.Count).End(xlUp).Row
'~~> Loop through the range in Sheet 2 to match it with the range in Sheet1
For i = 1 To ws2LR
SearchString = ws2.Range("B" & i).Value
'~~> Search for the ID
Set aCell = ws1Rng.Find(What:=SearchString, LookIn:=xlValues, _
LookAt:=xlWhole, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
'~~> If found
If Not aCell Is Nothing Then
'~~> Append values
ws1.Cells(aCell.Row, 1).Value = ws2.Cells(i, 1).Value
ws1.Cells(aCell.Row, 3).Value = ws2.Cells(i, 2).Value
ws1.Cells(aCell.Row, 19).Value = ws2.Cells(i, 18).Value
ws1.Cells(aCell.Row, 20).Value = ws2.Cells(i, 19).Value
End If
Next i
'~~> Delete the accounts that need to be deleted
ws1.AutoFilterMode = False
With Range("A1", Range("A" & Rows.Count).End(xlUp))
.AutoFilter 1, "Delete"
On Error Resume Next
.Offset(1).SpecialCells(12).EntireRow.Delete
End With
ws1.AutoFilterMode = False
'~~> Removing New from Column B
ws1.Columns("B").Replace What:="New", _
Replacement:="", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
ws1.Columns("A").EntireColumn.Delete
Call SheetKiller
End Sub
Sub SheetKiller()
Dim s As Worksheet, t As String
Dim i As Long, K As Long
K = Sheets.Count
For i = K To 1 Step -1
t = Sheets(i).Name
If t = "CableRevised" Then
Application.DisplayAlerts = False
Sheets(i).Delete
Application.DisplayAlerts = True
End If
Next i
End Sub
So the part that only works when I run the Macro from Sheet1 is:
'~~> Delete the accounts that need to be deleted
ws1.AutoFilterMode = False
With Range("A1", Range("A" & Rows.Count).End(xlUp))
.AutoFilter 1, "Delete"
On Error Resume Next
.Offset(1).SpecialCells(12).EntireRow.Delete
End With
ws1.AutoFilterMode = False
I'm not sure why - is it acting as if it will only delete the rows from the ActiveSheet (which I guess would be the Sheet I run the Macro from?) ? Is it possible to make it work even if I run the Macro from Sheet2?
Thanks for any help you provide!
You need to explicitly refer to ranges on ws1. As written, your code is looking for ranges on the active sheet.
Try this:
'~~> Delete the accounts that need to be deleted
ws1.AutoFilterMode = False
With ws1.Range("A1", ws1.Range("A" & ws1.Rows.Count).End(xlUp))
.AutoFilter 1, "Delete"
On Error Resume Next
.Offset(1).SpecialCells(12).EntireRow.Delete
End With
ws1.AutoFilterMode = False
I was trying to write a code. I 've applied a filter and then I need to apply one more filter after few lines. But the second filter is not getting applied. Here is my code-
Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function
Sub occ_const_ashish()
Dim wb As Worksheet
Dim bldscrng As Range
Dim wb1 As String
Dim i As String, j As String
Dim arr() As Variant
Dim arrTemp() As Variant
Set wb = Sheets(ActiveSheet.Name)
wb1 = ActiveSheet.Name
wb.Activate
LC = Sheets(wb1).Cells(1, Columns.Count).End(xlToLeft).Column
' Sets the search range as A1 to the last column with a header on the Run sheet
Set sRange = Sheets(wb1).Range("A1", Cells(1, LC))
' With the search range
With sRange
' Set Rng as the cell where "Country" is found
Set cntryrng = .Find(What:="CNTRYCODE", After:=.Cells(1), _
LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
If Not cntryrng Is Nothing Then
' Define LastRow as the last row of data under the Due Date header
LR = Sheets(wb1).Cells(Rows.Count, cntryrng.Column).End(xlUp).Row
' Copy from the Due Date header down to the last row of that column and paste to A1 of Paste Report Here sheet
'Set rngSourceRange1 = Sheets(wb1).Range(cntryrng(2), Cells(LR, cntryrng.Column))
Set rngSourceRange1 = Sheets(wb1).Range(cntryrng(2), Cells(LR, cntryrng.Column))
For Each cell In rngSourceRange1
i = cell.Value
rw = cell.Row
'MsgBox i
With ThisWorkbook.Sheets("Construction")
arr = Application.Transpose(.Range(.Cells(2, 1), .Cells(.Cells(.Rows.Count, 1).End(xlUp).Row, 1)).Value2)
End With
'arr1 = Application.Transpose(Sheets(wb1).Range(Sheets(wb1).Cells(2, 5), Sheets(wb1).Cells(Sheets(wb1).Cells(Sheets(wb1).Rows.Count, 5).End(xlUp).Row, 5)).Value2)
If IsInArray(i, arr) Then
'arrayTemp = Filter(arr1, i)
'MsgBox Join(arrayTemp, ",")
With ThisWorkbook.Sheets("Construction")
.AutoFilterMode = False
.Range("A1:E1").AutoFilter
.Range("A1:E1").AutoFilter Field:=1, Criteria1:=i
End With
With sRange
' Set Rng as the cell where "Country" is found
Set bldscrng = .Find(What:="BLDGSCHEME", After:=.Cells(1), _
LookIn:=xlValues, LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
col1 = bldscrng.Cells(1, 1).Column
j = Cells(rw, col1).Value
If j = "" Then
Cells(rw, LC + 1).Value = "BLDSCHEME is BLANK"
'MsgBox "bldscheme is blank"
Else
'MsgBox j
With ThisWorkbook.Sheets("Construction")
arr1 = Application.Transpose(.Range(.Cells(2, 3), .Cells(.Cells(.Rows.Count, 3).End(xlUp).Row, 3)).Value2)
End With
If IsInArray(j, arr1) Then
'MsgBox "scheme found"
With ThisWorkbook.Sheets("Construction")
If ActiveSheet.AutoFilterMode = False Then Range("A1:E1").AutoFilter
.Range("A1:E1").AutoFilter
.Range("A1:E1").AutoFilter Field:=1, Criteria1:=i
.Range("A1:E1").AutoFilter Field:=3, Criteria1:=j
End With
Else
'MsgBox "scheme not found"
Cells(rw, LC + 1).Value = "BLDSCHEME is INVALID"
End If
End If
End With
Else
MsgBox "Country not found"
End If
Next cell
End If
End With
End Sub
The problem is here:
If ActiveSheet.AutoFilterMode = False Then ...
Here you check if the AutoFilterMode is false while you have applied a filter in the previous lines. So it goes to the Else part and shows: MsgBox "scheme not found".
Modify this part of the code as below to comprehend what I mean:
With ThisWorkbook.Sheets("Construction")
.AutoFilterMode = False
Debug.Print .AutoFilterMode 'before applying autofilter
.Range("A1:E1").AutoFilter
Debug.Print .AutoFilterMode 'after applying autofilter
.Range("A1:E1").AutoFilter Field:=1, Criteria1:=i
End With
Also, when you want to use this much if-statements try to make the indentation clear and have some comments (maybe numbering) to make your code legible. Moreover, you can consider using Select Case.
How can I highlight a single row a color if text in column A = X
Using Row 4 as an example:
What i'm ultimately trying to get is if Cell in Column A is = X then change row color from Range("B4:N4") to Black And Text.Color to White from Range("F4:N4")
Ultimately I would want it to be something like Range(Cells(i, "B"), Cells(LastRow, LastCol)) but only color one row.
This is what i am working with so far.
Sub Header()
Application.ScreenUpdating = False
Dim sht2 As Worksheet
Set sht2 = ThisWorkbook.Worksheets("Email Form")
sht2.Activate
sht2.Unprotect
Dim LastRow As Long, LastCol As Long
Dim rng As Range, c As Range
Dim WholeRng As Range
Dim i As Integer
On Error GoTo 0
With sht2
Set rng = .Cells
LastRow = rng.Find(What:="*", After:=rng.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
LastCol = rng.Find(What:="*", After:=rng.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Column
'MsgBox wholerng.Address
Set WholeRng = Range(Cells(i, "B"), Cells(LastRow, LastCol)).Rows
For i = 4 To LastRow
If sht2.Cells(i, 1).Value = "X" Then
With WholeRng
With .Interior
.PatternColorIndex = xlAutomatic
.Color = 1
.TintAndShade = 0
.Font.Color = 0
End With
End With
End If
Next i
Dim b As Boolean
For Each rng In WholeRng.Rows
If Not rng.Hidden Then
If b Then rng.Interior.Color = 1
b = Not b
End If
Next
End With
Set sht2 = Nothing
Set rng = Nothing
Set WholeRng = Nothing
Application.ScreenUpdating = False
End Sub
VBA Conditional Formatting.
Option Explicit
Sub Header()
Dim sht2 As Worksheet
Dim firstRow As Long, lastRow As Long, lastCol As Long
'Application.ScreenUpdating = false
On Error GoTo 0
Set sht2 = ThisWorkbook.Worksheets("Email Form")
firstRow = 4
With sht2
.Activate
.Unprotect
lastRow = .Cells.Find(What:="*", After:=.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
lastCol = .Cells.Find(What:="*", After:=.Cells(1), Lookat:=xlPart, LookIn:=xlFormulas, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Column
'black row, white text B:N
With .Range(.Cells(firstRow, "B"), .Cells(lastRow, lastCol))
'optionally remove any pre-existing CFRs
.FormatConditions.Delete
With .FormatConditions.Add(Type:=xlExpression, Formula1:="=UPPER($A4)=CHAR(88)")
.Interior.ThemeColor = xlThemeColorLight1
.Font.ThemeColor = xlThemeColorDark1
.SetFirstPriority
.StopIfTrue = False
End With
End With
'don't display values from B:E
With .Range(.Cells(firstRow, "B"), .Cells(lastRow, "E"))
With .FormatConditions.Add(Type:=xlExpression, Formula1:="=UPPER($A4)=CHAR(88)")
.NumberFormat = ";;;"
End With
End With
'I tnhink you want to reProtect the worksheet here
.Protect
End With
Application.ScreenUpdating = True
End Sub
I think you can achieve your goal using Conditional Formatting:
You can create a condition for each format setting for the two different ranges.
Select one range at a time, then from the Home tab, create a New Conditional Formatting Rule, choose to Use a Formula and then enter a formula like:
=$A2="X"
Note that when using relative/mixed references in conditional formatting, it will be compared to the first cell in the range you are working with. I've selected range B2:N7 to apply formatting to, so the mixed reference needs to be created as it should apply to the B2 cell. You can't see it, but the reference automatically changes for all other cells in the same range, the same as if you were filling a formula across the rest of the range. For example, the formatting for the K5 cell will be dependent on the value in $A5 (because the column reference is fixed but the row reference is dynamic).
Then set the background colour or font colour you want for the range specified. This condition will check column A of the corresponding row.
I re-wrote some of your code and added comments to show you why. But by and large, I followed your original approach.
Sub Header()
Dim Sht2 As Worksheet
Dim LastRow As Long, LastCol As Long
Dim IsBlack As Boolean, FillPattern As Long
Dim Rng As Range
Dim R As Long
' Set sht2 = ThisWorkbook.Worksheets("Email Form")
Set Sht2 = ThisWorkbook.Worksheets("Taylor")
' On Error GoTo 0 ' this is the default: no need to set
Application.ScreenUpdating = False
With Sht2
.Activate ' no need to activate this sheet
.Unprotect
' this is the whole sheet: Easier to refer to it as .Cells
' Set rng = .Cells
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
' LastRow = Rng.Find(What:="*", After:=Rng.Cells(1), Lookat:=xlPart, _
' LookIn:=xlFormulas, SearchOrder:=xlByRows, _
' SearchDirection:=xlPrevious, MatchCase:=False).Row
' LastCol = Rng.Find(What:="*", After:=Rng.Cells(1), Lookat:=xlPart, _
' LookIn:=xlFormulas, SearchOrder:=xlByColumns, _
' SearchDirection:=xlPrevious, MatchCase:=False).Column
' MsgBox "Last row = " & LastRow & vbCr & _
' "Last column = " & LastCol
For R = 4 To LastRow
IsBlack = Not CBool(StrComp(.Cells(R, 1).value, "X", vbTextCompare))
FillPattern = CLng(Array(xlNone, xlSolid)(Abs(IsBlack)))
Set Rng = .Range(.Cells(R, 1), .Cells(R, LastCol))
With Rng.Interior
If .Pattern <> FillPattern Then
.Pattern = FillPattern
If IsBlack Then
.PatternColorIndex = xlAutomatic
.ThemeColor = xlThemeColorLight1
End If
.TintAndShade = 0
.PatternTintAndShade = 0
Rng.Font.ColorIndex = Array(xlAutomatic, 2)(Abs(IsBlack))
End If
End With
Next R
End With
' VBA does this cleanup automatically at the end of the sub
' Set sht2 = Nothing
' Set Rng = Nothing
Application.ScreenUpdating = False
End Sub
In Excel sheet2 i have Columns A & D for Name, B & E Start Date and column C & F is End Date and a Form with ComboBox (loaded with names) and two Textboxes.
I want when I click submit button it will search the columns for a name that matches the ComboBox value and then write the values of the two TextBoxes into the right adjacent two EMPTY cells
Private Sub CommandButton4_Click()
Dim irow As Long
Dim ws As Worksheet
Set ws = Worksheets("Sheet2")
With ws
.Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0).Value = Me.Combo.Value
.Cells(.Rows.Count, "B").End(xlUp).Offset(1, 0).Value = Me.sttdate.value
.Cells(Rows.Count, "C").End(xlUp).Offset(1, 0).Value = Me.enddate.Value
End With
With Me
.Combo.Value = ""
.startdate.Value = ""
.enddate.Value = ""
End With
End Sub
This code is adding value of all form into Columns A B & C
This should do the trick. I added some checks based on what you wrote in your explanation in case it helps.
Private Sub CommandButton4_Click()
Dim irow As Long
Dim ws As Worksheet
Set ws = Worksheets("Sheet2")
With ws
irow = .Range("A" & .Rows.Count).End(xlup).Row
Dim rFound as Range
Set rFound = .Range("A1:A" & iRow).Find(Me.Combo.Value, lookat:=xlWhole)
If not rFound is Nothing Then
If IsEmpty(rFound.Offset(,1)) and IsEmtpy(rFound.Offset(,2)) Then
rFound.Offset(,1) = Me.sttdate.value
rFound.Offset(,2) = Me.enddate.value
With Me
.Combo.Value = ""
.startdate.Value = ""
.enddate.Value = ""
End With
Else
Msgbox "Name already has values"
End If
Else
Msgbox "Name not Found"
End If
End Sub
This should work just fine :
Private Sub CommandButton4_Click()
Dim irow As Long, _
wS As Worksheet, _
NextRow As Long, _
cF As Range
Set wS = Worksheets("Sheet2")
With wS
With .Range("A:A")
'First, define properly the Find method
Set cF = .Find(What:=Me.Combo.Value, _
After:=.Cells(1, 1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlNext, _
MatchCase:=False, _
SearchFormat:=False)
End With
'If there is a result, keep looking with FindNext method
If Not cF Is Nothing Then
If cF.Offset(0, 1) <> vbNullString Then
Set cF = cF.End(xlToRight).Offset(0, 1)
cF.Value = Me.sttdate.Value
cF.Offset(0, 1).Value = Me.EndDate.Value
Else
.Cells(cF.Row, "B").Value = Me.sttdate.Value
.Cells(cF.Row, "C").Value = Me.EndDate.Value
End If
Else
NextRow = .Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0).Row
.Cells(NextRow, "A").Value = Me.Combo.Value
.Cells(NextRow, "B").Value = Me.sttdate.Value
.Cells(NextRow, "C").Value = Me.EndDate.Value
End If
End With
With Me
.Combo.Value = ""
.StartDate.Value = ""
.EndDate.Value = ""
End With
End Sub
My query is if I insert row using a button, it should also add serial numbers to the rows like 1,2,3 etc...
I have the below code here in Sheet1 of the worksheet for adding the serial numbers when I add rows
Private Sub Worksheet_Change1(ByVal Target As Range)
Dim StartNum As Integer
Dim FirstCell As Integer
Dim LastCell As Integer
StartNum = 2
FirstCell = 3
LastCell = 17
Application.EnableEvents = False
Do While FirstCell <= LastCell
Range("B" & FirstCell).Value = StartNum
FirstCell = FirstCell + 1
StartNum = StartNum + 1
Loop
Range("B" & LastCell + 1).Value = ""
Application.EnableEvents = True
End Sub
The below code is written in module1 to insert rows with formula of A1 copied to new rows
Sub Macro2()
Rows("2:2").Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Range("B1:D1").Select
Selection.AutoFill Destination:=Range("B1:D2"), Type:=xlFillDefault
Range("B1:D2").Select
End Sub
Now my Question is how to call the private sub from the Module Macro2 code while inserting rows
Any suggestions, waiting for your replies at the earliest.
Like I mentioned you do not need the Worksheet_Change code for this. Paste the below code in a module and try it..
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long, i As Long
'~~> Set this to the relevant sheet
Set ws = Sheets("Sheet1")
With ws
'~~> Insert at row 2
.Rows(2).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
'~~> Autofill B1:D1 to C1:D2
.Range("B1:D1").AutoFill Destination:=.Range("B1:D2"), Type:=xlFillDefault
'~~> Find the last row
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Else
lRow = 1
End If
'~~> Renumber the cells in Col B
For i = 1 To lRow
.Range("B" & i).Value = i
Next i
End With
End Sub
FOLLOWUP
Sub Sample()
Dim ws As Worksheet
Dim lRow As Long, i As Long, j As Double
'~~> Set this to the relevant sheet
Set ws = Sheets("Sheet1")
With ws
'~~> Insert at row 2
.Rows(2).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
'~~> Autofill B1:D1 to C1:D2
.Range("B1:D1").AutoFill Destination:=.Range("B1:D2"), Type:=xlFillDefault
'~~> Find the last row
If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
lRow = .Cells.Find(What:="*", _
After:=.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Else
lRow = 1
End If
'~~> Renumber the cells in Col B 1,1.1,1.2,1.3 etc
j = 1
For i = 1 To lRow
.Range("B" & i).Value = j
j = j + 0.1
Next i
End With
End Sub