Copy paste if contains certain value between three column - vba

I'm wondering about how to use "worksheet-change" the best way possible. Right now I use it to copy from one column to another column, in two different sheets. Whenever the column in Sheet1 is updated, column in Sheet2 will as well be updated. Using two columns is no problem and the code works fine!
My issue is whenever I want to use three columns. I want it to loop through column A and whenever it finds the word "Orange" in it, it should copy column B to coulmn A in sheet2.See my sheet for more detailed information.
If it finds Orange, it should only copy and updated the values "1,3,6" in Column B to column A in sheet2.
A code I tried with but didn't work, it copied everything to column B. If it is possible to use VLOOKUP, how do I do that? Because I tried that but it didnt updated whenever a cell was changed.
Dim x As Range
With Sheets("Sheet1")
Set x = .Columns(1).Find("Orange", LookIn:=xlValues, lookat:=xlWhole)
If Not x Is Nothing Then
.Columns(2).Copy Sheets("Sheet2").[B1]
End If
Set x = Nothing
End With
Example:
Workbook 1:
Column A
Orange
apple
Orange
Pear
Berry
Orange
Column B:
1
2
3
4
5
6
Should populate into a new sheet where only "1,3,6" is pasted in column B sheet2

I think you're better served by using the Workbook_SheetDeactivate event. By using this event (only when the user selects a sheet away from your source sheet), you're only performing the copy once. As an alternate and/or addition, you could perform the same copy from the Workbook_BeforeSave event (just in case the user saves and exits the workbook without changing sheets).
Option Explicit
Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
Dim activeRange As Range
Dim lastRow As Long
Dim c As Range
If Sh.Name = "Sheet1" Then
lastRow = Sh.Range("A" & Rows.Count).End(xlUp).Row
Set activeRange = Sh.Range("A1:A" & lastRow)
For Each c In activeRange
If c.Value = "Orange" Then
Sheets("Sheet2").Range(c.Offset(0, 1).Address) = c.Offset(0, 1).Value
End If
Next c
Debug.Print "done"
End If
End Sub

Try this:
Sub Fruity()
Application.ScreenUpdating = False
Dim LastRow As Integer
'Search code
LastRow = Cells.Find(What:="*", After:=[A1], SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Dim i As Long
For i = 1 To LastRow
If ThisWorkbook.Sheets("Sheet1").Range("A" & i) = "Orange" Then
Set NextCell = ThisWorkbook.Sheets("Sheet2").Cells(Rows.Count, "B").End(xlUp)
If NextCell = "" Then
NextCell = ThisWorkbook.Sheets("Sheet1").Range("B" & i)
Else
NextCell.Offset(1) = ThisWorkbook.Sheets("Sheet1").Range("B" & i)
End If
End If
Next i
Application.ScreenUpdating = True
End Sub
I am not sure what your target is for Worksheet_Change, so you'll have to clarify your question or add that on your own.
*edit: now puts the column B values from Sheet1 into column B in Sheet2 beginning at B1 instead of putting them in the row that corresponds with the found "Orange."

Related

How to do a partial look up in excel and get the data in next column till four rows in VBA

I have sheet 1 with Column name: Main task
MainTask
And, I have Sheet 2 where the Sub-tasks are given based on the characters between 1st and 2nd hyphen(-) of the Data in Main Task for eg: Under the main task column there is "Pyramid - IoT Forecast - Latin America - Argentina - 2017". So, based on the string " IoT Forecast" the sub tasks are given as in the below image.
Out Put:
Now In sheet 3 I need every title from the main task should be copied and pasted from the Sheet 1 and look for relevant sub tasks and pasted in the next column like the below image.
I have used, Wild cards, partial V-look up with Mid Function but only single sub task is populating. Please help me provide code in VBA.
Your Sheet 3 is identical to Sheet 2 but with the full main task in it instead of just the extract. I suggest the following method.
Create a column in Sheet 1 in which you write only the extract. This column would be identical in contents to column A of sheet 2. Use this formula to populate that column (where A2 contains the full main task).
=TRIM(LEFT(MID($A2,FIND("-",$A2)+1,100),FIND("-",MID($A2,FIND("-",$A2)+1,100))-1))
Make a copy of Sheet 2 as Sheet 3 and add a blank column B in it. Populate this column with this formula (where A:A is the column containing the full task, and C:C the column you added in step 1.
=INDEX('Sheet 1'!A:A,MATCH(A2,'Sheet 1'!C:C,0))
Replace the formulas in Sheet 3 with values (Copy / Paste values) and Remove column A from that sheet. Sort this sheet on what is now column A.
Remove the column you added in Sheet 1 to restore Sheet 1 to its original state.
You will need to do an array formula, something similar to the below where the sub category is in C1
=INDEX($A$2:$A$6,SMALL(IF(NOT(ISERROR(SEARCH("-" & $C$1 & "-",$A$2:$A$6))),ROW($A$2:$A$6)-1),ROWS($D$1:D1)))
If you are open to a VBA solution, you may try something like this.
The following code assumes that there are three sheets in the workbook named as "Sheet1", "Sheet2" and "Sheet3".
If the sheet names are different in your original workbook, please change them in the code in following lines before testing the code.
Set ws1 = Sheets("Sheet1")
Set ws2 = Sheets("Sheet2")
Set ws3 = Sheets("Sheet3")
Place the following code on a Standard Module and run the code to get the desired output on Sheet3.
Sub LookupData()
Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As Worksheet
Dim rng As Range, cell As Range, MainTask As Range
Dim lr2 As Long, lr3 As Long
Dim MainTaskStr As String, wht As String
Application.ScreenUpdating = False
Set ws1 = Sheets("Sheet1")
Set ws2 = Sheets("Sheet2")
Set ws3 = Sheets("Sheet3")
lr2 = ws2.Cells(Rows.Count, 1).End(xlUp).Row
Set rng = ws2.Range("A2:A" & lr2)
ws3.Cells.Clear
ws3.Range("A1:B1").Value = Array("Main Task", "Sub-Task")
If ws2.FilterMode Then ws2.ShowAllData
For Each cell In rng
If cell.Value <> MainTaskStr Then
MainTaskStr = cell.Value
lr3 = ws3.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row + 1
wht = "- " & cell.Value & " -"
Set MainTask = ws1.Range("A:A").Find(what:=wht, LookIn:=xlValues, lookat:=xlPart, MatchCase:=False)
If Not MainTask Is Nothing Then
With ws2.Rows(1)
.AutoFilter field:=1, Criteria1:=MainTaskStr
ws3.Range("A" & lr3) = MainTask.Value
ws2.Range("B2:B" & lr2).SpecialCells(xlCellTypeVisible).Copy ws3.Range("B" & lr3)
End With
End If
End If
Next cell
If ws2.FilterMode Then ws2.AutoFilterMode = False
ws3.UsedRange.Columns.AutoFit
Application.ScreenUpdating = True
End Sub

Find non zero value in column G on sheet 1, return value of Column C in that row to sheet 2 (VBA)

My first sheet is set up like this:
I want to find the non zero values in column G. Then I want to read the corresponding name in column C. I, then, want to return the value of the name to a cell on Sheet 2.
At this point, it doesn't matter what cell it returns to in sheet 2. It sounds like a VLOOKUP or INDEXMATCH but my VBA isn't good enough to figure out the formatting of it. This is some code that I tried and I can get it to return the name. But I don't know how to do it for all non zeros or how to have it print to sheet 2. Need a loop or need to figure out look ups!
code:
For Each c In Range("G6").Cells
If c.Value > 0 Then
PlayerName = Range(Cells(Selection.Row, 3).Address).Value
End If
Exit For
Next c
The following code will find the first row which has a number greater than 0 in column G (starting at row 6), and write the value in column C of that row to cell X5 of Sheet2.
With Worksheets("Sheet1")
For Each c In .Range("G6", .Cells(.Rows.Count, "G").End(xlUp)).Cells
If c.Value > 0 Then
Worksheets("Sheet2").Cells(5, "X").Value = c.Offset(0, -4).Value
Exit For ' Moved this inside the `If`, otherwise it will exit as soon as
' the first cell in the range is processed, irrespective of whether
' it was greater than 0 or not
End If
Next c
End With
Iterative version:
Dim s2Row as Long
s2Row = 5
With Worksheets("Sheet1")
For Each c In .Range("G6", .Cells(.Rows.Count, "G").End(xlUp)).Cells
If c.Value > 0 Then
Worksheets("Sheet2").Cells(s2Row, "X").Value = c.Offset(0, -4).Value
s2Row = s2Row + 1
End If
Next c
End With
Here is the logic you'll need. Will you be able to build the macro with this logic? It will help you understand how to maneuver rows that are greater than zero. Then you copy the column on that row y9ou need and paste it to the other sheet.
Sub macro1()
Dim myRng As Range, lastRow As Long
lastRow = ActiveSheet.Range("G65536").End(xlUp).Row
Set myRng = Sheet1.Range("G1:G" & lastRow)
For Each Rng In myRng
If IsNumeric(Rng.Value) And Rng.Value > 0 Then
Debug.Print "Cell " & Rng.Address & " has the number " & Rng.Value & " in row " & Rng.Row
End If
Next Rng
End Sub
Yes, except "G" is a column, not a row. Replace the debug.print line with WorkSheets("sheet name to copy from here").Rows(rng.row).Copy Destination:=WorkSheets("sheet name to copy to here").Range("A" & rowCounterVariable). Of course, change the sheet names to your actual sheet names.
Here I set the first row at 2 on the page to copy to. If you need to set it to the first available row then you need to research how to find the last used row on that page. Put these exact terms into Google "VBA EXCEL HOW TO FIND LAST USED ROW". I have an example of finding the last used row for the activesheet inside the code. We could give you fish today, and teach you how to fish. But you need to catch your own. We're not here to write code for you.
Sub macro2()
Dim myRng As Range, lastRow As Long, rowCounterVariable as long
rowCounterVariable = 2
lastRow = ActiveSheet.Range("G65536").End(xlUp).Row
Set myRng = Sheet1.Range("G1:G" & lastRow)
For Each Rng In myRng
If IsNumeric(Rng.Value) And Rng.Value > 0 Then
WorkSheets("sheet name to copy from here").Rows(rng.row).Copy Destination:=WorkSheets("sheet name to copy to here").Range("A" & rowCounterVariable)
rowCounterVariable = rowCounterVariable + 1
End If
Next Rng
End Sub

Select cells that fit in the range of the counter and concatenate what is selected from the range

I've been working on a Macro that i need to copy, concatenate what has been selected through the counter. e.g. is below
excel snapshot example
so what i want to do is set a count in column c from 1 to "infinite" because each worksheet varies to go up to 10 or hundreds and when the counter hits a value of 1 again to stop concatenate column D what is in the range from 1 to "the last digit it stopped before hitting 1 again" and paste it on a different sheet. I know little to nothing on VBA but I understand the copy and paste to different sheet part. I'm just stuck on the counter and the concatenate part. Here is the code i have so far(i edited it to resemble the example for better reference)
'select counter/concatenate
Sheets(1).Select
Columns("C").EntireColumn
Do
Columns("C").Count
For i = 1 To 9999
Loop While (i <= 1)
If i = 1 Then
select.columns("D")
after the count is where i am stuck. this count is what I've come up with looking at different variations of counters.
I suggest you Forget about column and use just one cell for easier understanding. A cell is a reference that allows you to refer to any other cells on the sheet by using Offsets. You may use two Loops, the outer one crawling the columns, the inner one working downward until it finds 1
Dim i As Long ' note that in VBA integer Overflows at 65535 rows
Dim s As String
Set aCell = Worksheet("Sheet1").Range("D1")
While aCell.Column < 255
i = 0
s = ""
While Not aCell.Offset(i, 0).Value = 1
s = s & aCell.Offset(1, 0).Value
Wend
' paste s somewhere by using range.value = s
Set aCell = aCell.Offset(0, 1)
Wend
By specifying the workbook and worksheet before the range, you may refer to the proper cell without being dependent on the active worksheet or range.
Hope this works for you.
You can try this (not tested):
Dim s As String, firstAddr as String
Dim f as range, iniCell As Range
With Worksheet("MySheet") '<--| change "MySheet" to your actual sheet name
With .Range("C1", .Cells(.Rows.Count, 3).End(xlUp))
Set f = .Find(What:=1, LookAt:=xlWhole, LookIn:=xlValues, After:=.Cells(.Rows.Count, 1))
If Not f Is Nothing Then
firstAddr = f.Address
Set iniCell = f
Set f = FindNext(f)
Do While f.Address <> firstAddr
s = s & Join(Range(iniCell, f.Offset(-1)).Offset(, 1), "")
' here code to paste s somewhere
Set iniCell = f
Set f = FindNext(f)
Loop
End If
End With
End With
Here's one I actually tested, using some random data in columns C and D.
You'll have to modify a little to get exactly where you want the data to go, but should get you in the right direction.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim i As Long
Dim s As String
Dim lastRow As Long
Dim c As Integer
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Set ws1 = ThisWorkbook.Sheets("Sheet1")
Set ws2 = ThisWorkbook.Sheets("Sheet2")
lastRow = ws1.Cells.Find("*", searchorder:=xlByRows, searchdirection:=xlPrevious).Row
'This will get an accurate last row
c = 1
For i = 1 To lastRow
s = s & ws1.Cells(i, 4).Value 'Build the string
If ws1.Cells(i + 1, 3).Value = 1 Or ws1.Cells(i + 1, 3).Value = "" Then
ws2.Cells(c, 1).Value = s
s = ""
c = c + 1
'If the next cell to check is 1 or blank, then copy the values to the next cell in order on sheet2
End If
Next
End Sub
Walking through it, lastRow is set using the last row in the sheet with a value in it. Then, c is set to one, although you could set this to the last available row in ws2 using the same process. After that it just steps through the rows from 1 To LastRow building strings and transferring the value to ws2 when it's about to hit a 1.

how can I compare 3 different columns of data in 3 different worksheets and highlight them in excel 2007?

so I have two worksheets with data, I want to compare column A of worksheet 1 to column A of worksheet 2 . Worksheet 1 is a template and worksheet 2 is a data report. Column A for both worksheets are item #s, worksheet 1 updates item #s and data from the report in worksheet 2. I want to create a formula or I guess vba code (I know nothing about VBA) whatever I can that will compare the item#s. I want the formula/code to pull the data from the report in worksheet 2 to the corresponding item #s in the template of worksheet 1 and high light any new item #s in the report(column A) of worksheet 2 that are not in worksheet 1 and then add those new high lighted item #s and its data to worksheet 1.
The range of data in column A of worksheet 1 is less than the range of data in column A of worksheet 2 that im trying to compare and pull from.
I thought about creating a IF formula in worksheet 2 to show me which item number exist, which are new but because the range of data in column A of worksheet 1 is less than column A of worksheet 2 I end getting an error value, I think creating a vba may be better but im not sure . Any advice, please give step by step detail/image of what to do. So far in general for the template I have a vlookup to pull the data BUT I need to know which items are new and highlight/pull them. Also if I could either delete or label the items numbers that is discontinued as discontinued that would be great. I think so far when I do a vlookup the items that are in worksheet 1 and not worksheet 2 come up as #N/A are the discontinued items. I have excel 2007, I hope you can help.
Sample Sheet1 and Sheet2
Output after updating using Vlookup
I am trying to compare three different columns of data in three worksheets and highlight the differences using VBA. I am very new to VBA and I don't know a lot about programming. So far this is what I've done:
worksheet1:
Sub compare_cols()
Dim myRng As Range
Dim lastCell As Long
'Get the last row
Dim lastRow As Integer
lastRow = ActiveSheet.UsedRange.Rows.Count
'Debug.Print "Last Row is " & lastRow
Dim c As Range
Dim d As Range
Application.ScreenUpdating = False
For Each c In Worksheets("worksheet1").Range("A2:A" & lastRow).Cells
For Each d In Worksheets("worksheet2").Range("A2:A" & lastRow).Cells
c.Interior.Color = vbGreen
If (InStr(1, d, c, 1) > 0) Then
c.Interior.Color = vbWhite
Exit For
End If
Next
Next
For Each c In Worksheets("worksheet2").Range("A2:A" & lastRow).Cells
For Each d In Worksheets("worksheet1").Range("A2:A" & lastRow).Cells
c.Interior.Color = vbYellow
If (InStr(1, d, c, 1) > 0) Then
c.Interior.Color = vbWhite
Exit For
End If
Next
Next
Application.ScreenUpdating = True
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
Worksheet 2:
Sub compare_cols()
Dim myRng As Range
Dim lastCell As Long
'Get the last row
Dim lastRow As Integer
lastRow = ActiveSheet.UsedRange.Rows.Count
'Debug.Print "Last Row is " & lastRow
Dim c As Range
Dim d As Range
Application.ScreenUpdating = False
For Each c In Worksheets("worksheet2").Range("A2:A" & lastRow).Cells
For Each d In Worksheets("worksheet3").Range("A2:A" & lastRow).Cells
c.Font.Color = rgbRed
If (InStr(1, d, c, 1) > 0) Then
c.Font.Color = rgbBlack
Exit For
End If
Next
Next
For Each c In Worksheets("worksheet3").Range("A2:A" & lastRow).Cells
For Each d In Worksheets("worksheet2").Range("A2:A" & lastRow).Cells
c.Interior.Color = vbRed
c.Font.Color = rgbWhite
If (InStr(1, d, c, 1) > 0) Then
c.Interior.Color = vbWhite
c.Font.Color = rgbBlack
Exit For
End If
Next
Next
Application.ScreenUpdating = True
End Sub
.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
End Sub
Problems I'm having:
in comparing worksheet1 and worksheet2, data that is not in worksheet2 are highlighted green in worksheet1, and data that is not in worksheet1 are highlighted yellow in worksheet2.
some of the data in worksheet2 for example are highlighted in yellow but are found in worksheet1, which shouldn’t happen. Then in comparing worksheet2 and worksheet3, items that are not in worksheet3 have a red colored font, in worksheet2, and items that are not in worksheet2 are highlighted red with a white font, in worksheet3.
data in worksheet2 for example have a red colored font but are found in worksheet3, which shouldn’t happen.
Can you please tell me why my VBA code isn't working, or what I else I can do?
If you want to do this automatically - it's about using VBA. But you don't have any knowledge of it, so I will not give you ready VBA solution.
To achieve your goal you can use Remove duplicates. With this you will create list of unique items - this will be list of all items from workbook1 and workbook2. Later you can create column with vlookup function as you did before. If item was found you will get Qty as you wanted, if not you will get #N/D which you can highlight using conditional formatting.
I guess it should solve your problem without VBA.
Would conditional formatting work for your needs? Here's a way to highlight cells that appear in another range (or don't appear, if you throw a "not(" in the mix).
http://www.techrepublic.com/blog/microsoft-office/use-conditional-formatting-to-compare-lists-in-excel/
I hope it helps!
JSR

Copy cells from specified column, removing duplicates

I'm newbie in VBA, what I need to do is to copy rows from specified column into a column on the other worksheet, but I want to copy just one occurance of each word, for example
Column "F"
dog
dog
cat
dog
In the result I need to have new Worksheet called "Animals" with:
Column "A" Column "B"
1 dog
2 cat
Here is a sub routine that will do exactly what you want: slap a list of unique elements in Sheet1 column F into column A of sheet2 and rename the sheet "animals". You could tweak this so that instead of it changing the name of sheet2 it can create a new sheet if you like.
Sub UniqueList()
Application.ScreenUpdating = False
Dim lastRow As Long
Dim i As Long
Dim dictionary As Object
Set dictionary = CreateObject("scripting.dictionary")
Sheet1.Activate
lastRow = Sheet1.Cells(Rows.count, "F").End(xlUp).row
On Error Resume Next
For i = 1 To lastRow
If Len(cells(i, "F")) <> 0 Then
dictionary.Add cells(i, "F").Value, 1
End If
Next
Sheet2.range("a1").Resize(dictionary.count).Value = _
Application.Transpose(dictionary.keys)
Application.ScreenUpdating = True
MsgBox dictionary.count & " unique cell(s) were found and copied."
End Sub
How it works: I use a dictionary file, which will automatically take out any dupes, then slap the list of entries into sheet2.
Do you need to do this in VBA at all?
If you just want to get a unique copy of your list, select the unsorted, non-unique column contents including the header, then hit the Advanced... button on the Sort and Filter pane of the Data ribbon. You can ask it to copy to another location and tick Unique records only.
Recording this activity and looking at the VBA, this is how it looks:
Range("A1:A4").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("B1"), Unique:=True
here is a solution:
Option Explicit
Sub copyNoDuplicates()
Dim rLastCell As Range
Dim cell As Range, i As Long
Dim cAnimals As Collection
Set cAnimals = New Collection
With ActiveWorkbook.Worksheets("Sheet1")
'Find last used cell
Set rLastCell = .Range("F65536").End(xlUp)
'Parse every animal and put it in a collection
On Error Resume Next
For Each cell In .Range("F2:F" & rLastCell.Row)
cAnimals.Add cell.Value, CStr(cell.Value)
Next cell
On Error GoTo 0
End With
With ActiveWorkbook.Worksheets("Sheet2")
For i = 1 To cAnimals.Count
.Range("A" & i).Value = i
.Range("B" & i).Value = cAnimals(i)
Next i
End With
End Sub