I receive an excel file with the below format:
But I need it to be the below format:
I have the blow code but it's not working.
Sub Format_Click()
Dim ws1 As Worksheet
Set ws1 = Sheets("Sheet1")
Dim ws2 As Worksheet
Set ws2 = Sheets("Sheet2")
Dim count As Integer
Dim rng As Range
Set rng = ws1.UsedRange
ws2.Cells(1, 1) = "Contract"
ws2.Cells(1, 2) = "Code"
ws2.Cells(1, 3) = "Price"
For i = 1 To rng.Columns.count
For j = 2 To rng.Rows.count
count = ws2.Range("A" & ws2.Rows.count).End(xlUp).Row
ws2.Cells(count + 1, 1) = rng.Cells(1, i)
ws2.Cells(count + 1, 2) = rng.Cells(j, i)
ws2.Cells(count + 1, 3) = rng.Cells(j, 1)
Next j
Next i
End Sub
Take all the data into an array, loop trough once and detect categories (categories are values with no qty according to your image).
My code shows output in same sheet but in can bee easily adapted to make output in a different worksheet:
Sub test()
Dim i As Long
Dim j As Long
Dim LR As Long
Dim MyData As Variant
Dim CurrentCat As String
LR = Range("A" & Rows.Count).End(xlUp).Row
MyData = Range("A1:B" & LR).Value
Range("D1").Value = "Category"
Range("E1").Value = "Name"
Range("F1").Value = "Qty"
j = 2
For i = LBound(MyData) To UBound(MyData) Step 1
If MyData(i, 2) = "" Then
'its a Category if there is no qty
CurrentCat = MyData(i, 1)
Else
'there is data
Range("D" & j).Value = CurrentCat
Range("E" & j).Value = MyData(i, 1)
Range("F" & j).Value = MyData(i, 2)
j = j + 1
End If
Next i
Erase MyData
End Sub
Consider reading about arrays, pretty useful:
Excel VBA Array – The Complete
Guide
Related
I have a data like this :
A049
A050
A051
A053
A054
A055
A056
A062
A064
A065
A066
And I want the output like :
As you can see, I want the ranges which are in consecutive order
I am trying some thing like this:
Private Sub CommandButton1_Click()
Set wb = ThisWorkbook
lastRow = wb.Sheets("Sheet1").Range("A" & wb.Sheets("Sheet1").Rows.Count).End(xlUp).Row
For i = 2 To lastRow
r = wb.Sheets("Sheet1").Range("A" & i).Value
If wb.Sheets("Sheet1").Range("A" & i).Value = wb.Sheets("Sheet1").Range("A" & i+1).Value
Next i
End Sub
But not helping me
Am feeling charitable so have tried some code which should work. It assumes your starting values are in A1 down and puts results in C1 down.
Sub x()
Dim v1, v2(), i As Long, j As Long
v1 = Range("A1", Range("A" & Rows.Count).End(xlUp)).Value
ReDim v2(1 To UBound(v1, 1), 1 To 2)
For i = LBound(v1, 1) To UBound(v1, 1)
j = j + 1
v2(j, 1) = v1(i, 1)
If i <> UBound(v1, 1) Then
Do While Val(Right(v1(i + 1, 1), 3)) = Val(Right(v1(i, 1), 3)) + 1
i = i + 1
If i = UBound(v1, 1) Then
v2(j, 2) = v1(i, 1)
Exit Do
End If
Loop
End If
If v1(i, 1) <> v2(j, 1) Then v2(j, 2) = v1(i, 1)
Next i
Range("C1").Resize(j, 2) = v2
End Sub
Try the below code
Private Sub CommandButton1_Click()
Set wb = ThisWorkbook
lastRow = wb.Sheets("Sheet1").Range("A" & wb.Sheets("Sheet1").Rows.Count).End(xlUp).Row
Dim lastNum, Binsert As Integer
Dim firstCell, lastCell, currentCell As String
Binsert = 1
lastNum = getNum(wb.Sheets("Sheet1").Range("A1").Value)
firstCell = wb.Sheets("Sheet1").Range("A1").Value
For i = 2 To lastRow
activeNum = getNum(wb.Sheets("Sheet1").Range("A" & i).Value)
currentCell = wb.Sheets("Sheet1").Range("A" & i).Value
If (activeNum - lastNum) = 1 Then
'nothing
Else
lastCell = wb.Sheets("Sheet1").Range("A" & (i - 1)).Value
wb.Sheets("Sheet1").Range("B" & Binsert).FormulaR1C1() = firstCell
If (firstCell <> lastCell) Then
wb.Sheets("Sheet1").Range("C" & Binsert).FormulaR1C1() = lastCell
End If
Binsert = Binsert + 1
firstCell = wb.Sheets("Sheet1").Range("A" & i).Value
End If
lastNum = activeNum
Next i
'last entry
wb.Sheets("Sheet1").Range("B" & Binsert).FormulaR1C1() = firstCell
If (firstCell <> currentCell) Then
wb.Sheets("Sheet1").Range("C" & Binsert).FormulaR1C1() = currentCell
End If
End Sub
Public Function getNum(ByVal num As String) As Integer
getNum = Val(Mid(num, 2))
End Function
Another solution. It loops backwards from last row to first row.
Option Explicit
Public Sub FindConsecutiveValues()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim lRow As Long 'find last row
lRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
Dim lVal As String 'remember last value (stop value)
lVal = ws.Range("A" & lRow).Value
Const fRow As Long = 2 'define first data row
Dim i As Long
For i = lRow To fRow Step -1 'loop from last row to first row backwards
Dim iVal As Long
iVal = Val(Right(ws.Range("A" & i).Value, Len(ws.Range("A" & i).Value) - 1)) 'get value of row i without A so we can calculate
Dim bVal As Long
bVal = 0 'reset value
If i <> fRow Then 'if we are on the first row there is no value before
bVal = Val(Right(ws.Range("A" & i - 1).Value, Len(ws.Range("A" & i - 1).Value) - 1)) 'get value of row i-1 without A
End If
If iVal - 1 = bVal Then
ws.Rows(i).Delete 'delete current row
Else
If lVal <> ws.Range("A" & i).Value Then 'if start and stop value are not the same …
ws.Range("B" & i).Value = lVal 'write stop value in column B
End If
lVal = ws.Range("A" & i - 1).Value 'remember now stop value
End If
Next i
End Sub
I am stuck in my vba code and seems I setup a loop wrong. Really appreciate for some advices! Thank you very much!!
Sub code()
Dim lastRow As Long
Dim k As Integer
Dim rowPtr As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
For rowPtr = 2 To lastRow
If Range("A" & rowPtr + 1) <> Range("A" & rowPtr) Then
k = 1
Range("B" & rowPtr) = k
Else
If Range("A" & rowPtr + 1) = Range("A" & rowPtr) Then
Range("B" & rowPtr) = k
End If
k = k + 1
End If
Next
End Sub
Above is my code and now my VBA result is like this:
screenshot
Column C is my ideal result of the code
Rank Reps (Repeating Values)
Adjust the values in the constants section.
Note that Range("A" & rowPtr) is the same as Cells(rowPtr, "A") or Cells(rowPtr, 1), and Range("A" & Rows.Count) is the same as Cells(Rows.Count, "A") or Cells(Rows.Count, 1).
Option Explicit
Sub rankReps()
Const FirstRow As Long = 2
Const sCol As String = "A"
Const dCol As String = "B"
Dim cOffset As Long: cOffset = Columns(dCol).Column - Columns(sCol).Column
Dim LastRow As Long: LastRow = Range(sCol & Rows.Count).End(xlUp).Row
If LastRow < FirstRow Then
MsgBox "No data", vbCritical, "No Data"
Exit Sub
End If
' Write first.
Range(sCol & FirstRow).Offset(, cOffset).Value = 1
' Write remainder.
If LastRow > FirstRow Then
Dim cCell As Range ' Current Cell
Dim r As Long ' Row Counter
Dim rk As Long: rk = 1 ' Rank Counter
For r = FirstRow + 1 To LastRow ' +1: the first is already written
Set cCell = Range(sCol & r)
If cCell.Value = cCell.Offset(-1).Value Then
rk = rk + 1
Else
rk = 1
End If
cCell.Offset(, cOffset).Value = rk
Next r
End If
End Sub
Public Sub UpdateRankings(ByVal ws As Worksheet)
' Adjust as necessary.
Const firstRow As Long = 3
Const colGroupId As Long = 1
Const colRanking As Long = 6
Dim row As Long
With ws
' First value defaults to 1.
row = firstRow
.Cells(row, colRanking).Value = 1
' Remaining rows.
row = row + 1
Do While .Cells(row, colGroupId).Value <> ""
' If group id is the same as the previous row, increment rank.
If .Cells(row, colGroupId).Value = .Cells(row - 1, colGroupId).Value Then
.Cells(row, colRanking).Value = .Cells(row - 1, colRanking).Value + 1
' If group id has changed, reset rank to 1.
Else
.Cells(row, colRanking).Value = 1
End If
' Next row.
row = row + 1
Loop
End With
End Sub
Please, try the next way:
Sub Countcode()
Dim lastRow As Long, k As Long, rowPtr As Long
lastRow = cells(rows.count, 1).End(xlUp).row
k = 1
For rowPtr = 2 To lastRow
If Range("A" & rowPtr) = Range("A" & rowPtr + 1) Then
Range("B" & rowPtr) = k: k = k + 1
Else
If Range("A" & rowPtr) = Range("A" & rowPtr - 1) Then
Range("B" & rowPtr) = k: k=1
Else
k = 1
Range("B" & rowPtr) = k
End If
End If
Next
End Sub
One approach is:
Sub numberIt2()
Dim cl As Range, equal As Integer ' equal initial value is 0
Set cl = Range("A1")
Do While cl <> ""
cl.Offset(0, 1) = equal + 1
Set cl = cl.Offset(1)
equal = IIf(cl = cl.Offset(-1), equal + 1, 0)
Loop
End Sub
How do i put multiple values from different cells (eg: values that lies below header x rel and y rel previously obtained by my program) and put them in the same cell which lies the same row as device d?(not manually select in excel or selectively using coding). What my current code does is to locate the x and y values of reliability fails then stored them in array(not sure is it correct or not) but after that how to concatenate them in the same cell shown in "After"?
Public Sub FindAndConvertforreliabilityfails()
Dim i As Integer
Dim j As Integer
Dim lastRow As Long
Dim myRng As Range
Dim mycell As Range
Dim MyColl As Collection
Dim myIterator As Variant
Set MyColl = New Collection
Dim xpos As integr, ypos As Integer
MyColl.Add "x rel"
MyColl.Add "y rel"
Dim LastCol As Integer
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
For i = 1 To LastCol
For j = 1 To lastRow
For Each myIterator In MyColl
Do While Sheets(1).Cells(1, j).Value <> ""
If Sheets(1).Cells(1, i).Value = myIterator Then
xpos(j) = Sheets(1).Cells(Rows.Count, 6).End(xlUp).Offset(1, 0)
Else
ypos(j) = Sheets(1).Cells(Rows.Count, 7).End(xlUp).Offset(1, 0)
End If
Loop
Next
Next
' how to continue from here for the concatenate portion?
End Sub
Before
After
Currently
Try this. This will give you the expected output.
Private Sub Test()
Dim output As Variant
Dim outputrow As Integer
output = ""
outputrow = 0
For i = 2 To 5 'change 5 to lastrow of F&G Column.
If Cells(i, "B").Value = 0 Then
output = output & "(" & Cells(i, "F").Value & "," & Cells(i, "G").Value & "),"
Else
Cells(i, "E") = Left(output, Len(output) - 1)
output = "(" & Cells(i, "F").Value & "," & Cells(i, "G").Value & "),"
End If
Next i
Cells(i, "E") = Left(output, Len(output) - 1)
End Sub
I want to check if the text value in a cell is the same as in the cell below with a for loop.
If the value in Cell(1) and Cell(2) does not match I want the value from Cell(3) written in Cell(4).
I get an error
"Overflow (Error 6)"
Dim i As Integer
For i = 1 To Rows.Count
If Cells(2 + i,21) = Cells(3 + i,21) Then
i = i + 1
Else
a = Cells(3 + i, 1)
j = j + 1
Cells(228 + j, 3) = a
End If
Next i
End Sub
I have a production output and a timeline from 6 am to 12 am and I want to create a timetable as seen below.
Screenshot:
You could use
Option Explicit
Sub test()
Dim LastRowA As Long, i As Long, j As Long, LastRowW As Long
Dim StartTime As Date, EndTime As Date, strOutPut
j = 0
With ThisWorkbook.Worksheets("Sheet1")
LastRowA = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 3 To LastRowA
If i > j - 1 Then
StartTime = .Range("A" & i).Value
strOutPut = .Range("U" & i).Value
For j = i + 1 To LastRowA + 1
If strOutPut <> .Range("U" & j).Value Then
EndTime = .Range("A" & j - 1).Value
LastRow = .Cells(.Rows.Count, "W").End(xlUp).Row
.Range("W" & LastRow + 1).Value = StartTime
.Range("X" & LastRow + 1).Value = EndTime
.Range("Y" & LastRow + 1).Value = strOutPut
Exit For
End If
Next j
End If
Next i
End With
End Sub
Result
Here I'm using a dictionary which will store every time for every product comma separated, so later will split that and take the first and last occurrence:
Sub TimeTable()
'Declare an array variable to store the data
'change MySheet for your sheet name
arr = ThisWorkbook.Sheets("MySheet").UsedRange.Value 'this will store the whole worksheet, the used area.
'Declare a dictionary object
Dim Products As Object: Set Products = CreateObject("Scripting.Dictionary")
'Loop through the array
Dim i As Long
For i = 3 To UBound(arr) 'start from row 3 because of your screenshoot
If arr(i, 21) = vbNullString Then GoTo NextRow 'if column U is empty won't add anything
If Not Products.Exists(arr(i, 21)) Then '21 is the column index for column U
Products.Add arr(i, 21), arr(i, 1)
Else
Products(arr(i, 21)) = arr(i, 21) & "," & arr(i, 1)
End If
NextRow:
Next i
Erase arr
'Redim the array to fit your final data, 4 columns and as many rows as products
ReDim arr(1 To Products.Count + 1, 1 To 4)
'Insert the headers
arr(1, 1) = "Time"
arr(1, 4) = "Product / Error"
'Now loop through the dictionary
Dim Key As Variant, MySplit As Variant
i = 2
For Each Key In Products.Keys
MySplit = Split(Products(Key), ",")
arr(i, 1) = MySplit(LBound(MySplit))
arr(i, 2) = "-"
arr(i, 3) = MySplit(UBound(MySplit))
arr(i, 4) = Key
i = i + 1
Next Key
'I don't know where are you going to paste your data, so I'm making a new worksheet at the end of your workbook
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
With ws
.Range("A1").Resize(UBound(arr), UBound(arr, 2)).Value = arr
.Range("A1:C1").Merge
End With
End Sub
I have a table which contains merged cells both column and rows as shown in attached picture. I want to unmerge "Only" rows while leaving columns merged. Consider the following snippet of table. In the image attached "Contract
For y = 1 To lRow
p = 1
c = y
d = 1
z = lRow + y
t = Cells(y, 1).Value
For x = 1 To t
Cells(z, p).Value = Cells(c, d).Value
Cells(c, d).Select
' Debug.Print
Selection.End(xlToRight).Select
c = ActiveCell.Row
d = ActiveCell.Column
p = p + 1
Next
Next
Sub ColorMergedCells()
Dim c As Range
Dim startcolumn, endcolumn, startrow, endrow As Long
For Each c In ActiveSheet.UsedRange
If c.MergeCells And c.MergeArea.Rows.Count >= 2 Then
c.Interior.ColorIndex = 28
With c.MergeArea.Rows
.UnMerge
' .Formula = c.Formula
End With
'
'startcolumn = ActiveCell.Column
'endcolumn = Selection.Columns.Count + startcolumn - 1
'startrow = ActiveCell.Row
'endrow = Selection.Rows.Count + startrow - 1
End If
Next
End Sub
Based on your snapshot of requirements , I have wrote a very simple code which shall appear to be crude but I have kept it this way so that you can adjust its various elements as per your actual data. Sample data taken by me and results obtained are shown in the snapshot pasted below, which is followed by code.
Sub Merge_unmerge()
Dim wb As Workbook
Dim ws As Worksheet
Dim rng As Range
Dim cell As Range
Dim LastRow As Long
Dim LastCol As Long
Set wb = ThisWorkbook
Set ws = wb.Sheets(1)
With ws
LastRow = .Cells(.Rows.Count, "B").End(xlUp).Row
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
Set rng = ws.Range("A1:D" & LastRow)
For Each cell In rng
cell.UnMerge
Next cell
For i = 2 To LastRow
If Range("A" & i) = "" Then
Range("A" & i).Value = Range("A" & i - 1).Value
End If
Next i
For i = 2 To LastRow
If Range("D" & i) = "" Then
Range("D" & i).Value = Range("D" & i - 1).Value
End If
Next i
For i = 1 To LastRow Step 2
Range("B" & i & ":C" & i).Merge
Range("B" & i & ":C" & i).HorizontalAlignment = xlCenter
Next i
End Sub
Never mind. I solved for the issue at hand. Posting if it helps others.
Sub ColorMergedCells()
Dim c As Range
Dim startcolumn, endcolumn, startrow, endrow As Long
For Each c In ActiveSheet.UsedRange
If c.MergeCells And c.MergeArea.Rows.Count >= 2 Then
c.Interior.ColorIndex = 28
startcolumn = c.Column
endcolumn = c.MergeArea.Columns.Count + startcolumn - 1
startrow = c.Row
endrow = c.MergeArea.Rows.Count + startrow - 1
With c.MergeArea.Rows
.UnMerge
.Formula = c.Formula
End With
For J = startrow To endrow
Application.DisplayAlerts = False
Range(Cells(J, startcolumn), Cells(J, endcolumn)).Merge
Application.DisplayAlerts = True
Next
End If
Next
End Sub