The below macros works for - I have a workbook with two sheets (Active and Archive). And in Active sheet i have AB column that contains Active or Archive status. If its status Archive macros cuts and moves the row to the sheet Archive. This macros works perfect.
Now i need to add some other sheets to excel and named them (New, Accepted, Rejected) and of course i add the same status to the column AB. Now i want macros to do the same if AB = Archive or New or Accepted or Rejected cut and move the row to the sheet named Archive or New or Accepted or Rejected.
I tried it by myself but can't do it.
Need ur help. Thanks in advance.
Private Sub CommandButton1_Click()
Dim x As Integer
Dim y As Integer
Dim i As Integer
Dim shSource As Worksheet
Dim shTarget1 As Worksheet
Set shSource = ThisWorkbook.Sheets("Active")
Set shTarget1 = ThisWorkbook.Sheets("Archive")
If shTarget1.Cells(2, 28).Value = "" Then
x = 2
Else
x = shTarget1.Cells(2, 28).CurrentRegion.Rows.Count + 1
End If
i = 2
Do Until shSource.Cells(i, 28) = ""
If shSource.Cells(i, 28).Value = "Archive" Then
shSource.Rows(i).Copy
shTarget1.Cells(x, 1).PasteSpecial Paste:=xlPasteValues
shSource.Rows(i).Delete
x = x + 1
GoTo Line1
End If
i = i + 1
Line1: Loop
End Sub
You can set up multiple variables and choose the right ones in a select case. There is some repetition here that could get cleaned up with arrays.
Sub CommandButton1_Click()
Dim x As Integer 'archive target counter
Dim y As Integer 'new target counter
Dim z As Integer 'accepted target counter
Dim w As Integer 'rejected target counter
'the above could be an array if we were trying to generalize
Dim i As Integer 'counts rows in original sheet
Dim shSource As Worksheet
Dim shTarget1 As Worksheet 'archive sheet
Dim shTarget2 As Worksheet 'new sheet
Dim shTarget3 As Worksheet 'accepted sheet
Dim shTarget4 As Worksheet 'rejected sheet
'these 4 could also be an array, as could their names, in which case some things become loops and the select case could be written out
Set shSource = ThisWorkbook.Sheets("Active")
Set shTarget1 = ThisWorkbook.Sheets("Archive")
Set shTarget2 = ThisWorkbook.Sheets("New")
Set shTarget3 = ThisWorkbook.Sheets("Accepted")
Set shTarget4 = ThisWorkbook.Sheets("Rejected")
If shTarget1.Cells(2, 28).Value = "" Then
x = 2
Else
x = shTarget1.Cells(2, 28).CurrentRegion.Rows.Count + 1
End If
If shTarget2.Cells(2, 28).Value = "" Then
y = 2
Else
y = shTarget2.Cells(2, 28).CurrentRegion.Rows.Count + 1
End If
If shTarget3.Cells(2, 28).Value = "" Then
z = 2
Else
z = shTarget3.Cells(2, 28).CurrentRegion.Rows.Count + 1
End If
If shTarget4.Cells(2, 28).Value = "" Then
w = 2
Else
w = shTarget4.Cells(2, 28).CurrentRegion.Rows.Count + 1
End If
i = 2
Do Until shSource.Cells(i, 28) = ""
Select Case shSource.Cells(i, 28).Value
Case "Archive":
shSource.Rows(i).Copy
shTarget1.Cells(x, 1).PasteSpecial Paste:=xlPasteValues
shSource.Rows(i).Delete
x = x + 1
Case "New":
shSource.Rows(i).Copy
shTarget2.Cells(y, 1).PasteSpecial Paste:=xlPasteValues
shSource.Rows(i).Delete
y = y + 1
Case "Accepted":
shSource.Rows(i).Copy
shTarget3.Cells(z, 1).PasteSpecial Paste:=xlPasteValues
shSource.Rows(i).Delete
z = z + 1
Case "Rejected":
shSource.Rows(i).Copy
shTarget4.Cells(w, 1).PasteSpecial Paste:=xlPasteValues
shSource.Rows(i).Delete
w = w + 1
Case Else 'no cutting so move to next input line
i = i + 1
End Select
Loop
End Sub
EDIT: Below is the array based version that repeats itself less. Also, I found I kept overwriting my top row in the target sheets, so I added 2 (not 1) to the target counters when I initialized them. If the original was working in your context, you may switch it back.
Sub CommandButton1_Click()
Dim TargetCounters(3) As Integer
Dim TargetNames(3) As String
TargetNames(0) = "Archive"
TargetNames(1) = "New"
TargetNames(2) = "Accepted"
TargetNames(3) = "Rejected"
Dim i As Integer 'counts rows in original sheet
Dim shSource As Worksheet
Dim shTargets(3) As Worksheet
Set shSource = ThisWorkbook.Sheets("Active")
For i = 0 To 3
Set shTargets(i) = ThisWorkbook.Sheets(TargetNames(i))
If shTargets(i).Cells(2, 28).Value = "" Then
TargetCounters(i) = 2
Else 'there is stuff. Imagine for example it is in rows 2 to 7. Count will be 6. We need to start pasting in row 8
TargetCounters(i) = shTargets(i).Cells(2, 28).CurrentRegion.Rows.Count + 2 'changed this from orinal + 1
End If
Next i
i = 2
Dim MatchIndex As Integer
Do Until shSource.Cells(i, 28).Value = ""
'you could switch this case to a call on the application's match function against TargetNames
'if you take care with the case where it is not found and indexing being right and not off by 1
Select Case shSource.Cells(i, 28).Value
Case "Archive":
MatchIndex = 0
Case "New":
MatchIndex = 1
Case "Accepted":
MatchIndex = 2
Case "Rejected":
MatchIndex = 3
Case Else 'no cutting so set signal and we will move to next input line
MatchIndex = -1
End Select
If (MatchIndex = -1) Then
i = i + 1
Else
shSource.Rows(i).Copy
shTargets(MatchIndex).Cells(TargetCounters(MatchIndex), 1).PasteSpecial Paste:=xlPasteValues
shSource.Rows(i).Delete
TargetCounters(MatchIndex) = TargetCounters(MatchIndex) + 1
End If
Loop
End Sub
Related
I am new to stackoverflow.com and VBA. I have been searching the web for a VBA that will allow me to copy data from sheet 1 that I input and then paste into sheet 2 based off the a cell value match. Once it is copied, it would then clear the data on Sheet 1 without delete the rows.
I work in a call center, and this would be to update equipment based on the desk it is located at.
So I am hoping that once I input all the data into the fields on sheet 1, I can click an activex button and it will search for the desk number on sheet 2 in column A and then update the row (B:Q) with the data from sheet 1.
I have seen some VBA that will copy the data but it only copies to the next empty row of cells.
Here is the code that I have found but is just not right.
Sub MoveRowBasedOnCellValue()
Dim xRg As Range
Dim xCell As Range
Dim I As Long
Dim J As Long
Dim K As Long
I = Worksheets("Sheet1").UsedRange.Rows.Count
J = Worksheets("Sheet2").UsedRange.Rows.Count
If J = 1 Then
If Application.WorksheetFunction.CountA(Worksheets("Sheet2").UsedRange) = 0 Then J = 0
End If
Set xRg = Worksheets("Sheet1").Range("A5:Q5" & I)
On Error Resume Next
Application.ScreenUpdating = False
For K = 1 To xRg.Count
If CStr(xRg(K).Value) = ("A5") Then
xRg(K).EntireRow.Copy Destination:=Worksheets("Sheet2").Range("A" & J + 1)
J = J + 1
End If
Next
Application.ScreenUpdating = True
End Sub
Any help would be great!
Thanks.
Something like the code below? I assumed the desk number are on column A sheet1 starting at row 2. You will need to adjust the end rows for both sheet though.
Sub MoveRowBasedOnCellValue()
Dim s1 As Sheet1
Set s1 = Sheet1
Dim s2 As Sheet2
Set s2 = Sheet2
Dim s1StartRow As Integer
Dim s1EndRow As Integer
Dim s2StartRow As Integer
Dim s2EndRow As Integer
s1StartRow = 2
s1EndRow = 8
s2StartRow = 2
s2EndRow = 10
Application.ScreenUpdating = False
For i = s1StartRow To s1EndRow
For j = s2StartRow To s2EndRow
If s1.Cells(i, 1) = s2.Cells(j, 1) Then
s1.Range("B" & i & ":Q" & i).Copy
s2.Cells(j, 2).PasteSpecial xlPasteAll
Application.CutCopyMode = False
End If
Next j
Next i
Application.ScreenUpdating = True
End Sub
I am having trouble knowing how to code my dilemma. Below is my current code which works extremely well for comparing Sheet 3 Col B with Sheet 2 Col B. Once a match is found between both Col B's, the code then copies the adjacent cells from Sheet 3 Col A and C, and pastes the answer into Sheet 2 Col A and D respectively.
Sub ID()
Dim sheet1 As Worksheet, sheet2 As Worksheet, Sheet3 As Worksheet
Dim isFound As Boolean: isFound = False
Set sheet1 = Sheets(1)
Set sheet2 = Sheets(2)
Set Sheet3 = Sheets(3)
Dim Sheet3ColB, Sheet2ColB As Variant
Dim ii As Long, tt As Long, w As Long: w = 3
Sheet3ColA = Sheet3.Range("A2:C" & Sheet3.Cells(Sheet3.Rows.Count, 2).End(xlUp).Row).Value2
Sheet2ColB = sheet2.Range("B3:B" & sheet2.Cells(sheet2.Rows.Count, 2).End(xlUp).Row).Value2
For ii = LBound(Sheet2ColB) To UBound(Sheet2ColB)
isFound = False
For tt = LBound(Sheet3ColA) To UBound(Sheet3ColA)
'perform case insensitive (partial) comparison
If InStr(1, LCase(Sheet2ColB(ii, 1)), LCase(Sheet3ColA(tt, 2))) > 0 Then
sheet2.Cells(w, 1) = Sheet3ColA(tt, 1)
sheet2.Cells(w, 4) = Sheet3ColA(tt, 3)
w = w + 1
isFound = True
End If
Next
If Not isFound Then
sheet2.Cells(w, 2) = Sheet2ColB(ii, 1)
w = w + 1
End If
Next
End Sub
My only issue is that my data will have some duplicates. So when the Instr function runs, it will return more than one value (only a few times at best), for the single row. But all I need is for the code to copy and paste from the row that it is comparing at that time, and nothing more - So only the information from the row in question. My suggestion would be this, but it is returning an error:
sheet2.Cells(w, 1) = Sheet3ColA(tt & Cells.row, 1)
sheet2.Cells(w, 4) = Sheet3ColA(tt & Cells.row, 3)
All I need it to do is for it to take only the data from the same row in Sheet 3 and paste that info only into sheet 2, ignoring all other duplicates possible above/ below the data.
once a match is found, no need to go further with the inner loop, so my suggestion is
Sub ID()
Dim sheet1 As Worksheet, sheet2 As Worksheet, Sheet3 As Worksheet
Dim isFound As Boolean: isFound = False
Set sheet1 = Sheets(1)
Set sheet2 = Sheets(2)
Set Sheet3 = Sheets(3)
Dim Sheet3ColB, Sheet2ColB As Variant
Dim ii As Long, tt As Long, w As Long: w = 3
Sheet3ColA = Sheet3.Range("A2:C" & Sheet3.Cells(Sheet3.Rows.Count, 2).End(xlUp).Row).Value2
Sheet2ColB = sheet2.Range("B3:B" & sheet2.Cells(sheet2.Rows.Count, 2).End(xlUp).Row).Value2
For ii = LBound(Sheet2ColB) To UBound(Sheet2ColB)
isFound = False
For tt = LBound(Sheet3ColA) To UBound(Sheet3ColA)
'perform case insensitive (partial) comparison
If InStr(1, LCase(Sheet2ColB(ii, 1)), LCase(Sheet3ColA(tt, 2))) > 0 Then
sheet2.Cells(w, 1) = Sheet3ColA(tt, 1)
sheet2.Cells(w, 4) = Sheet3ColA(tt, 3)
w = w + 1
isFound = True
Exit for
End If
Next
If Not isFound Then
sheet2.Cells(w, 2) = Sheet2ColB(ii, 1)
w = w + 1
End If
Next
End Sub
I have two sheets data and PrevErrCheck. I am checking all occurrence of variable VarVal(this variable has data in E1 cell of PrevErrCheck) in sheet data and copy entire row to sheet PrevErrCheck. But the problem I am facing here is running macro multiple times overwriting data. I would like to keep the copied rows in sheet data and whenever I run next time, it should copy to next blank row.
I am using below code currently but bit confused to how to integrate the the option to find last row on PrevErrCheck and copy lines below that
Sub PrevErrCheck()
Dim spem As Workbook
Dim PrevErrCheck As Worksheet
Dim data As Worksheet
Dim xRg As Range
Dim xCell As Range
Dim I As Long
Dim J As Long
Dim K As Long
Set spem = Excel.Workbooks("SwitchPortErrorMonitor.xlsm")
Set PrevErrCheck = spem.Worksheets("PrevErrCheck")
Set data = spem.Worksheets("data")
spem.Worksheets("PrevErrCheck").Activate
VarVal = PrevErrCheck.Cells(1, "E").Value
I = data.UsedRange.Rows.count
J = PrevErrCheck.UsedRange.Rows.count
If J = 1 Then
If Application.WorksheetFunction.CountA(PrevErrCheck.UsedRange) = 0 Then J = 0
End If
Set xRg = data.Range("X:X")
On Error Resume Next
Application.ScreenUpdating = False
J = 3
For K = 1 To xRg.count
If CStr(xRg(K).Value) = VarVal And Not IsEmpty(VarVal) Then
xRg(K).EntireRow.Copy Destination:=PrevErrCheck.Range("A" & J + 1)
PrevErrCheck.Range("X" & J + 1).ClearContents
J = J + 1
End If
Next
Application.ScreenUpdating = True
End Sub
You have J = 3 before the loop, that may be a problem. xRg.count always returns 1048576, you should use something more specific. Try this:
Set spem = Excel.Workbooks("SwitchPortErrorMonitor.xlsm")
Set PrevErrCheck = spem.Worksheets("PrevErrCheck")
VarVal = PrevErrCheck.Cells(1, "E").Value
If IsEmpty(VarVal) Then Exit Sub
Set data = spem.Worksheets("data")
spem.Worksheets("PrevErrCheck").Activate
I = data.UsedRange.Rows.Count
J = PrevErrCheck.UsedRange.Rows.Count + 1
If J = 2 Then
If IsEmpty(PrevErrCheck.Cells(1, 1)) Then J = 1
End If
' If J = 1 Then
' If Application.WorksheetFunction.CountA(PrevErrCheck.UsedRange) = 0 Then J = 0
' End If
' Set xRg = data.Range("X:X")
' On Error Resume Next
' Application.ScreenUpdating = False
' J = 3
For K = 1 To I
If CStr(data.Cells(K, "X").Value) = VarVal Then
data.Cells(K, 1).EntireRow.Copy Destination:=PrevErrCheck.Range("A" & J)
PrevErrCheck.Range("X" & J).ClearContents
J = J + 1
End If
Next
' Application.ScreenUpdating = True
End Sub
I have a excel sheet looks like this: "Sheet1" & "Sheet2" and I wanted the result as shown in "Sheet3".
Sample Data
Eventually I would like to put a "Button" in a separate sheet (Control Panel) and when clicking on it I need to combine the data from "Sheet1" and "Sheet2" with the transpose effect as shown in "Sheet3".
How can I automate this using macro since there are ~2000 "rows" in Sheet 1 and ~1000 in Sheet 2. I'm new to macro so hopefully I can make this automated otherwise I'm copying and pasting all of them manually.
Thanks!
It might be helpful to use a function that returns the last row of a worksheet:
Public Function funcLastRow(shtTarget As Worksheet, Optional iColLimit As Integer = -1) As Long
If iColLimit = -1 Then
iColLimit = 256
End If
Dim rowMaxIndex As Long
rowMaxIndex = 0
Dim ctrCols As Integer
For ctrCols = 1 To iColLimit
If shtTarget.Cells(1048576, ctrCols).End(xlUp).Row > rowMaxIndex Then
rowMaxIndex = shtTarget.Cells(1048576, ctrCols).End(xlUp).Row
End If
Next ctrCols
funcLastRow = rowMaxIndex
End Function
You could use it simply like so:
Dim lLastRow As Long
lLastRow = funcLastRow(Sheets(1))
Please let us know if that worked for you thanks
Here is an all formula solution (No Macro)
Data is in Sheet1 A to I and Sheet2 A to G
I am assuming you have only 6 departments. although if you have additional, the formulas need very little or may be no modification.
In Sheet 3
Get the userID repeated six times
A2 = INDEX(Sheet1!A:A,1+QUOTIENT(ROW()-ROW($A$2)+6,6))
Get Name, Gender & Country
B2 = VLOOKUP($A2,Sheet1!$A$2:$I$3000,COLUMNS($A$1:B$1),FALSE)
C2 = VLOOKUP($A2,Sheet1!$A$2:$I$3000,COLUMNS($A$1:C$1),FALSE)
D2 = VLOOKUP($A2,Sheet1!$A$2:$I$3000,COLUMNS($A$1:D$1),FALSE)
Get Access to department. The "" & ... is to avoid 0 in case the resulting cell was blank.
E2 = "" & IF(SUMPRODUCT(--(Sheet1!$A$1:$I$1=F2))>0,HLOOKUP(F2,Sheet1!$A$1:$I$3000,MATCH(A2,Sheet1!$A$1:$A$3000,0),FALSE),HLOOKUP(F2,Sheet2!$A$1:$G$3000,MATCH(A2,Sheet2!$A$1:$A$3000,0),FALSE))
F2:F7 the departments are Input manually (no formula). F8 is linked to F2 so that the depts repeat when dragged down
G2 = "" & IF(SUMPRODUCT(--(Sheet1!$A$1:$I$1=F2))>0,INDEX(Sheet1!$I$1:$I$3000,MATCH(A2,Sheet1!$A$1:$A$3000,0)),INDEX(Sheet2!$G$1:$G$3000,MATCH(A2,Sheet1!$A$1:$A$3000,0)))
If you need, I can prepare a google sheet to demo. Cheers.
This code works very well for Transpose and concatenate of big data.
Sub ConcatData()
Dim X As Double
Dim DataArray(5000, 2) As Variant
Dim NbrFound As Double
Dim Y As Double
Dim Found As Integer
Dim NewWks As Worksheet
Cells(1, 1).Select
Let X = ActiveCell.Row
Do While True
If Len(Cells(X, 1).Value) = Empty Then
Exit Do
End If
If NbrFound = 0 Then
NbrFound = 1
DataArray(1, 1) = Cells(X, 1)
DataArray(1, 2) = Cells(X, 2)
Else
For Y = 1 To NbrFound
Found = 0
If DataArray(Y, 1) = Cells(X, 1).Value Then
DataArray(Y, 2) = DataArray(Y, 2) & ", " & Cells(X, 2)
Found = 1
Exit For
End If
Next
If Found = 0 Then
NbrFound = NbrFound + 1
DataArray(NbrFound, 1) = Cells(X, 1).Value
DataArray(NbrFound, 2) = Cells(X, 2).Value
End If
End If
X = X + 1
Loop
Set NewWks = Worksheets.Add
NewWks.Name = "SummarizedData"
Cells(1, 1).Value = "Names"
Cells(1, 2).Value = "Results"
X = 2
For Y = 1 To NbrFound
Cells(X, 1).Value = DataArray(Y, 1)
Cells(X, 2).Value = DataArray(Y, 2)
X = X + 1
Next
Beep
MsgBox ("Summary is done!")
End Sub
I tried to make a program that separates the duplicates and outputs to other worksheets. The data is composed of 3 columns and thousands of rows. First column is a unique number, second column is the material name, and third is the description of the material.
I tried:
Sub duplicates_separation()
Dim duplicate(), i As Long
Dim delrange As Range, cell As Long
Dim delrange2 As Range
Dim shtIn As Worksheet, shtOut As Worksheet
Set shtIn = ThisWorkbook.Sheets("process")
Set shtOut = ThisWorkbook.Sheets("output")
x = 2
y = 1
Set delrange = Range("b1:b30000") 'set your range here
Set delrange2 = Range("c1:c30000")
For cell = 1 To delrange.Cells.Count
If Application.CountIf(delrange, delrange(cell)) > 1 Then
ReDim Preserve duplicate(i)
duplicate(i) = delrange(cell).Address
i = i + 1
End If
Next
For i = UBound(duplicate) To LBound(duplicate) Step -1
Range(duplicate(i)).Value = shtOut.Cells(x, 1).Value
x = x + 1
Next i
End Sub
But it goes to Error 9, Out of Range. It worked before, I don't know why it goes to an error. Anybody know why?
UPDATE
error happen in For i = UBound(duplicate) To LBound(duplicate) Step -1
what i chaged :
from
range(duplicate(i)).entirerow.cut
shtout.cells(x,1).paste
to
Range(duplicate(i)).Value = shtOut.Cells(x, 1).Value
UPDATE It's works now!
Sub duplicates_separation()
Dim duplicate(), i As Long
Dim delrange As Range, cell As Long
Dim delrange2 As Range
Dim shtIn As Worksheet, shtOut As Worksheet
Set shtIn = ThisWorkbook.Sheets("process")
Set shtOut = ThisWorkbook.Sheets("output")
x = 2
y = 1
Set delrange = shtIn.Range("b1:b30000") 'set your range here
Set delrange2 = shtIn.Range("c1:c30000")
'search duplicates in 2nd column
For cell = 1 To delrange.Cells.Count
If Application.CountIf(delrange, delrange(cell)) > 1 Then
ReDim Preserve duplicate(i)
duplicate(i) = delrange(cell).Address
i = i + 1
End If
Next
'search duplicates in 3rd column
For cell = 1 To delrange2.Cells.Count
If Application.CountIf(delrange2, delrange2(cell)) > 1 Then
ReDim Preserve duplicate(i)
duplicate(i) = delrange2(cell).Address
i = i + 1
End If
Next
'add header
shtOut.Cells(1, 1).Resize(1, 3).Value = _
Array("Material Number", "Short Description", "Long Description")
'print duplicates
For i = UBound(duplicate) To LBound(duplicate) Step -1
shtOut.Cells(x, 1).EntireRow.Value = shtIn.Range(duplicate(i)).EntireRow.Value
x = x + 1
Next i
End Sub
This works if you run the code while the sheet that contains the data is selected.
If not, and the sheet currently selected have no value in b1:b30000, then this line:
For i = UBound(duplicate) To LBound(duplicate) Step -1
will produce the Error 9 since you were not able to initialize duplicate variable since you only Redim Preserve when your If statement was satisfied.
To avoid the error, properly declare the variable delrange like this:
Set delrange = shtIn.Range("b1:b30") 'i assumed only that shtIn is the source sheet, change otherwise.
Set delrange2 = shtIn.Range("c1:c30")
and then change this line as well:
For i = UBound(duplicate) To LBound(duplicate) Step -1
shtOut.Cells(x, 1).Value = shtIn.Range(duplicate(i)).Value
x = x + 1
Next i
Again, i assumed that you are writing on shtOut and not the other way around like what you did in your code.