I have this table:
Quantity Name
1 A
3 C1
3 C2
4 D
I'm trying to make this table change to:
Quantity Name
1 A
1 A
3 C1
3 C1
3 C1
3 C2
3 C2
3 C2
4 D
4 D
4 D
4 D
But the result is not as expect: Result
Pls help my solve this problem.
Thanks!
Here is my code:
Sub newrow()
Dim xRg As Range
Dim xAddress As String
Dim I, xNum, xLastRow, xFstRow, xCol, xCount As Long
On Error Resume Next
xAddress = ActiveWindow.RangeSelection.Address
Set xRg = Application.InputBox("Select a range to use(single column):", "KuTools For Excel", xAddress, , , , , 8)
If xRg Is Nothing Then Exit Sub
Application.ScreenUpdating = False
xLastRow = xRg(1).End(xlDown).Row
xFstRow = xRg.Row
xCol = xRg.Column
xCount = xRg.Count
Set xRg = xRg(1)
For I = xLastRow To xFstRow Step -1
xNum = Cells(I, xCol)
If IsNumeric(xNum) And xNum > 0 Then
Rows(I + 1).Resize(Cells(I, xCol) - Cells(I - 1, xCol)).Insert
xCount = xCount + xNum
End If
Next
xRg.Resize(xCount, 1).Select
Application.ScreenUpdating = True
End Sub
First of all …
If you Dim xFstRow, xCol, xCount As Long then only xCount is of type Long all the others are of type Variant. You need to specify a type for every variable!
Dim xFstRow As Long, xCol As Long, xCount As Long
Don't ever use On Error Resume Next without proper error handling. This only hides error messages but the errors still occur you just cannot see them. Therefore you cannot debug/fix your code. Remove it completely or implement a complete error handling instead.
You need to copy the row before you insert, otherwise you just insert empty rows.
I suggest the following code:
Option Explicit
Public Sub AddRowsFromQantities()
Dim SelAddress As String
SelAddress = ActiveWindow.RangeSelection.Address
Dim SelRange As Range
Set SelRange = Application.InputBox("Select a range to use(single column):", "KuTools For Excel", SelAddress, , , , , 8)
Dim fRow As Long
fRow = SelRange.Row 'first row of selected rang
Dim lRow As Long
lRow = fRow + SelRange.Rows.Count - 1 'last row of selected range
'find last used row within the selected range
If Cells(Rows.Count, 1).End(xlUp).Row < lRow Then
lRow = Cells(Rows.Count, 1).End(xlUp).Row
End If
Application.ScreenUpdating = False
Dim iRow As Long
For iRow = lRow To fRow Step -1
If IsNumeric(Cells(iRow, 1)) Then
Dim Quantity As Long
Quantity = Cells(iRow, 1).Value
If Quantity > 1 Then
Rows(iRow).Copy
Rows(iRow).Resize(RowSize:=Quantity - 1).Insert
End If
End If
Next iRow
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Related
I have the following VBA code for excel
Dim k As Integer, z As Integer
Dim sourceSht As Worksheet
Dim destSht As Worksheet
z = 0
Set sourceSht = Sheets("sheet1")
Set destSht = Sheets("sheet2")
DoEvents
For k = 1 To 5000
If k < 3 Or (k - 1) Mod 3 <> 0 Then
z = z + 1
sourceSht.Columns(k).Copy destSht.Columns(z)
End If
Next
This code was working perfectly for rows (changed this part"sourceSht.Columns(k).Copy destSht.Columns(z)").
but I can not make it work for columns. I want excel to copy the first 2 columns then skip the third one, then copy 2 again, skip one and etc... can somebody help me and explain what am I doing wrong?
I'm going to ignore the use of mod and do a Step 3 with the loop:
Dim i as Long, j as Long
For i = 1 to 5000 Step 3
With sourceSht
If j = 0 Then
j = 1
Else
j = j + 2 'Copying 2 columns over, so adding 2 each time
End If
.Range(.Columns(i),.Columns(i+1)).Copy destSht.Range( destSht.Columns(j), destSht.Column(j+1))
End With
Next i
Something like that should do it for you
Alternate:
Sub tgr()
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim rCopy As Range
Dim rLast As Range
Dim LastCol As Long
Dim i As Long
Set wsSource = ActiveWorkbook.Sheets("Sheet1")
Set wsDest = ActiveWorkbook.Sheets("Sheet2")
On Error Resume Next
Set rLast = wsSource.Cells.Find("*", wsSource.Range("A1"), xlFormulas, , xlByColumns, xlPrevious)
On Error GoTo 0
If rLast Is Nothing Then Exit Sub 'No data
LastCol = rLast.Column
Set rCopy = wsSource.Range("A:B")
For i = 4 To LastCol Step 3
Set rCopy = Union(rCopy, wsSource.Columns(i).Resize(, 2))
Next i
rCopy.Copy wsDest.Range("A1")
End Sub
Try this (use count for the number of time you need to copy columns, t for the first columns you need to copy):
Sub copy_columns()
t = 1
Count = 1
Do Until Count = 10
Range(Columns(t), Columns(t + 1)).Copy
Cells(1, t + 3).Select
Selection.PasteSpecial Paste:=xlPasteValues
t = t + 3
Count = Count + 1
Loop
End Sub
I'm trying to make a macro that will look at a column and if it sees the value change then it inserts a new row. I've worked some code below but I'm jus getting Application-defined or object-defined error.
Sub FormatMyData()
Dim Col As Variant
Dim BlankRows As Long
Dim LastRow As Long
Dim R As Long
Dim StartRow As Long
Dim Value As String
Value = Worksheets("Sheet1").Cells(2, D).Value
Col = "D"
StartRow = 1
BlankRows = 1
LastRow = Cells(Rows.Count, Col).End(xlUp).Row
With Worksheets("Sheet1")
For R = LastRow To StartRow + 1 Step -1
If Worksheets("Sheet1").Cells(R, Col) <> Value Then
Worksheets("Sheet1").Cells(R + 1, Col).EntireRow.Insert Shift:=xlDown
Value = Cells(R + 2, Col)
End If
Next R
End With
End Sub
any help would be greatly appreciated.
You should also say where exactly the Error occurs, so we have an easier job to help you.
The things I found were the following:
use Sheets instead of Worksheets
in the line you read out the Value use .Cells(2, "D").Value
in your loop on changing your Value you´re using Cells without specifiing the Sheet
since you´re using a With on the Sheet, you can spare some code
so change your code like this:
Sub FormatMyData()
Dim Col As Variant
Dim BlankRows As Long
Dim LastRow As Long
Dim R As Long
Dim StartRow As Long
Dim Value As String
Value = Sheets("Sheet1").Cells(2, "D").Value
Col = "D"
StartRow = 1
BlankRows = 1
LastRow = Cells(Rows.Count, Col).End(xlUp).Row
With Sheets("Sheet1")
For R = LastRow To StartRow + 1 Step -1
If .Cells(R, Col) <> Value Then
.Cells(R + 1, Col).EntireRow.Insert Shift:=xlDown
Value = .Cells(R + 2, Col)
End If
Next R
End With
End Sub
I wanted to add a row in excel vba when ever the value in column A is 1, here is the code I wrote, but this returns a "subscript out of range error". What am I doing wrong?
Sub InsertRow()
Dim Col As Variant
Dim BlankRows As Long
Dim LastRow As Long
Dim R As Long
Dim StartRow As Long
Application.ScreenUpdating = False
Col = "A"
StartRow = 1
LastRow = 20
Worksheets("Sheet1").Activate
For R = StartRow To LastRow
If Cells(R, Col) = 1 Then
Cells(R, Col).EntireRow.Insert Shift:=xlDown
End If
Next R
Application.ScreenUpdating = True
End Sub
Code below tested and works.
With Worksheets("Sheet1")
Dim cntr as Long
For cntr = 20 to 5 Step - 1
If .Cells(cntr, 1) = 1 Then .cells(cntr,1).EntireRow.Insert Shift:=xlDown
Next
End With
Sub InsertRow()
Dim Col As Variant
Dim BlankRows As Long
Dim LastRow As Long
Dim R As Long
Dim StartRow As Long
Application.ScreenUpdating = False
Col = "A"
StartRow = 1
LastRow = 20
Worksheets("Sheet1").Activate
R = StartRow
Do While R <= LastRow
If Cells(R, Col) = 1 Then
Cells(R, Col).EntireRow.Insert Shift:=xlDown
R = R + 1
LastRow = LastRow + 1
End If
R = R + 1
Loop
Application.ScreenUpdating = True
End Sub
Note the setting of the value of R in the loop, as you are shifting the rows down, you are continually checking the same value and therefore adding a row each time so we need to increment R by 1 to skip past the 1 we just checked.
We also need to change the endpoint as we are pushing values past Row 20 by inserting so we also increment the LastRow variable. We cannot do this in a for loop in VBA, the for loop will terminate at 20 so I have changed to a while loop
As per the comment below, working backwards from 20 is far more elequent but since I didn't think of that I haven't put it in here :)
I have a description in Column A which contains some error code like ESFB-1 , ESFB-11 etc... with list of error codes in sheet2 a total of about 36 error codes
I have the below code written & works but the only problem is it is treating both ESFB-1 & ESFB-11 as same the list has about 35 error codes with similar nomenclature below is the code
enter code here
Sub sear()
Dim rng As Range
Dim str As String
Dim str1 As String
Dim val1 As Long
Dim val2 As Long
Dim col As Integer
Dim col2 As Integer
Dim row2 As Integer
Dim row As Integer
Dim var As Integer
Dim lastRow As Long
Dim lastrow1 As Long
Dim pos As Integer
lastRow = Sheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).row
lastrow1 = Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).row
var = 0
col = 1
row = 2
row2 = 2
pos = 0
Do While var <> 1
Do While row <= lastrow1
Do While pos = 0
str = Sheets("Sheet1").Cells(row, 1).Value
str1 = Sheets("Sheet2").Cells(row2, 1).Value
pos = InStrRev(str, str1, vbTextCompare)
row2 = row2 + 1
If row2 = lastRow Then Exit Do
Loop
If pos <> 0 Then
Cells(row, 7).Value = Sheets("Sheet2").Cells(row2 - 1, 1)
End If
Cells(row, 8).Value = pos & Sheets("Sheet1").Cells(row, 1)
pos = 0
row2 = 2
row = row + 1
Loop
var = 1
Loop
End Sub
Please suggest modifications which can help me find the exact error code from description
Instr will give you false positive like you are getting for ESFB-1 & ESFB-11 and hence you need a more robust check.
Is this what you are trying?
Sub Sample()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim lRow As Long
Dim Arws As Variant, tempAr As Variant
Dim rng As Range, aCell As Range
'~~> Set your sheets here
Set ws1 = Sheet1: Set ws2 = Sheet2
With ws2
lRow = .Range("A" & .Rows.Count).End(xlUp).row
'~~> Store the error codes in an array
Arws = .Range("A1:A" & lRow)
End With
With ws1
lRow = .Range("A" & .Rows.Count).End(xlUp).row
'~~> This is your range from 1st sheet
Set rng = .Range("A2:A" & lRow)
'~~> Loop through all cells and split it's contents
For Each aCell In rng
tempAr = Split(aCell.Value)
'~~> Loop through each split word in the array
For i = LBound(tempAr) To UBound(tempAr)
'~~> Check if exists in array
If ExistsInArray(Trim(tempAr(i)), Arws) Then
'~~> If it does then write to col B
aCell.Offset(, 1).Value = Trim(tempAr(i))
Exit For
End If
Next i
Next aCell
End With
End Sub
'~~> Function to check if a string is int he array
Function ExistsInArray(s As String, arr As Variant) As Boolean
Dim bDimen As Byte, i As Long
On Error Resume Next
If IsError(UBound(arr, 2)) Then bDimen = 1 Else bDimen = 2
On Error GoTo 0
Select Case bDimen
Case 1
On Error Resume Next
ExistsInArray = Application.Match(s, arr, 0)
On Error GoTo 0
Case 2
For i = 1 To UBound(arr, 2)
On Error Resume Next
ExistsInArray = Application.Match(s, Application.Index(arr, , i), 0)
On Error GoTo 0
If ExistsInArray = True Then Exit For
Next
End Select
End Function
Screenshot
I can't get this to loop through to the next row. The inner two loops are working fine from what i can tell using the debugger but it never goes to the next row. Any help would be appreciated.
Sub PopulateData()
Dim s1 As Worksheet
Dim s2 As Worksheet
Dim locationRow As Integer
Set s1 = ThisWorkbook.Sheets("Order_LVL")
Set s2 = ThisWorkbook.Sheets("sheet1")
Dim Lastrow As Integer
Lastrow = s1.Cells(Rows.Count, 1).End(xlUp).Row
Dim iRow As Integer
For iRow = 1 To Lastrow
Dim cellj As Range
For Each cellj In s1.Range("B:F")
locationRow = 1
Dim celli As Range
For Each celli In s2.Range("B1:F1")
Dim currentrow As Long
currentrow = iRow + 1
If s1.Cells(currentrow, cellj.Column).Value = 0 Then
ElseIf s1.Cells(currentrow, cellj.Column).Value <> s2.Cells(locationRow, celli.Column).Value And s2.Cells(currentrow, celli.Column).Value = 0 Then
s2.Cells(currentrow, celli.Column).Value = 0
Else: s2.Cells(currentrow, celli.Column).Value = 1 'indicates that this order features a line from this location
End If
Next celli
Next cellj
Next iRow
End Sub
Can you try this on some test data (Note I haven't tested it myself but re-written it with only two loops)
Sub PopulateData()
Dim s1 As Worksheet: Dim s2 As Worksheet
Dim rng As range: Dim rng2 As range
Dim cell: Dim header
With Application
.ScreenUpdating = False
End With
With ThisWorkbook
Set s1 = .Sheets("Order_LVL")
Set s2 = .Sheets("sheet1")
End With
With s1
Set rng = range(.Cells(1, 2), .Cells(.Cells(Rows.Count, 6).End(xlUp).Row, 6)) ' Used Range in Order_LVL
End With
Set rng2 = range(s2.Cells(1, 2), s2.Cells(1, 6)) 'Header range in sheet1
For Each cell In rng.Cells
For Each header In rng2.Cells
If cell.value = 0 Then
ElseIf cell.value <> header.value And s2.Cells(cell.Row, header.Column).value = 0 Then
s2.Cells(cell.Row, header.Column).value = 0 ' Not sure why you're doing this - if it is already 0 why set it back to 0. Left it in for continuity
Else
s2.Cells(cell.Row, header.Column).value = 1 ' indicates that this order features a line from this location
End If
Next header
Next cell
With Application
.ScreenUpdating = True
End With
End Sub
It should do what you want if I've understood correctly.