Situation:
I have an excel macro which imports a column of data into an existing sheet in the next free column, it also clears formatting of the previous column which will be set at the completion of the macro (the bit I'm trying to work out here).
I need the code to compare each cell in the new column to the previous column to see if there is a match, if no match then highlight the cell.
Problem:
I keep getting type mismatch errors, or the code does not run. My latest attempt (which incluces copying the unique data to a different sheet which would be a bonus if working) is below.
Dim rngCell As Range
For Each rngCell In Range(Cells(2, Worksheets("Data").Columns(LastColumn)), Cells(10000, Worksheets("Data").Columns(LastColumn)))
'I know hardcoding values is bad, but i did this for testing purposes
If WorksheetFunction.CountIf(Range(Cells(2, Worksheets("Data").Columns(LastColumn)), Cells(10000, Worksheets("Data").Columns(LastColumn))), rngCell) = 0 Then
Range("D" & Rows.Count).End(xlUp).Offset(1) = rngCell
End If
Next
Ideal outcome:
The code runs through and highlights unique values in column 1 (using column index references as each day a new column is imported).
The code copies the unique values to another sheet for ease of use.
Thanks in advance for any pointers or code.
Since you are only posting a part of your code, I'd have to assume that the part wher you insert and clear formatting is already working well.
Sometimes you define a worksheet, sometimes you don't so I'm not sure what sheet we are working with here.
But just to clarify, if you had data in column "A", and then ran the macro to paste data in column "B", would you want something like this:
prevCol = 1
lastCol = 2
Set Rng = Range(Cells(2, prevCol), Cells(100, prevCol))
Set Rng2 = Range(Cells(2, lastCol), Cells(100, lastCol))
For Each rngCell In Rng
If WorksheetFunction.CountIf(Rng2, rngCell) = 0 Then
rngCell.Interior.Color = RGB(250, 230, 20)
End If
Next
Where unique items in the column that existed before the new one got inserted are highligted?
So in the end, maybe something more like this:
Sub SubName()
Dim sht As Worksheet
Dim lastCol As Long, lastRow As Long
Set sht = Worksheets("Data") 'or whatever
' Instert column
' clear formatting
lastCol = sht.Cells(2, sht.Columns.Count).End(xlToLeft).Column
lastRow = sht.Cells(sht.Rows.Count, lastCol - 1).End(xlUp).Row
For Each rngCell In Range(Cells(2, lastCol - 1), Cells(lastRow, lastCol - 1))
If WorksheetFunction.CountIf(Range(Cells(2, lastCol), Cells(lastRow, lastCol)), rngCell) = 0 Then
rngCell.Interior.Color = RGB(250, 230, 20)
End If
Next
End Sub
Related
Hi Hopefully somebody can help as i am missing something in my code.
I am trying to loop through a dynamic row from the last knowing value to the new values, then add these new values as a column headr in starting in row 3.
I have the first portion and can get the new values to paste into next blank column. the issue is i can't work out how to offset to the next empty cell. rather than pasting all new values into the same cell.
Sub Testnewname()
Dim Nw2 As Integer
Dim c As Long
Dim D As Long
Dim Lcol1 As Long
Dim Lrow2 As Long
Lcol1 = Cells(3, Columns.Count).End(xlToLeft).Column '' Find last column available in row 3
Lrow2 = Cells(Rows.Count, 10).End(xlUp).Row ''Find last row where new info is put via a table defined by names =UNIQUE(Table1[[#Data],[Company]],FALSE,FALSE)
Nw2 = Sheets("Cost Table").Range("$H$10").Value ''value of the old number of cells used to start from in loop
c = Lcol1 + 1 ''allocate a varable to last column + 1
For D = Nw2 To Lrow2 ''for d (i) from cell 19 to last cell
Cells(D, 10).Copy 'copy cell value
Cells(3, c).PasteSpecial xlPasteValues ''this is where is would of thought pasteinto last column whichit does. What seems to happen is id doesnt move to next column when it reloops
Next D ''would of expected that when it goes onto next loop that the C (Lcol+1) would recalculate
ThisWorkbook.Worksheets("Cost Table").Range("H11").Copy
ThisWorkbook.Worksheets("Cost Table").Range("H10").PasteSpecial Paste:=xlPasteValues ' takes the value from a CountA function in H11 and pastes into H10 to update the last place a cell value was prior to running macro and updates Nw2 for running the macro again
Application.CutCopyMode = False
End Sub
I have tried to add in a Second loop for the column but this does nothing
For C = Lcol to Lcol + 1
For D = Nw2 To Lrow2
Cells(D, 10).Copy
Cells(3, c).PasteSpecial xlPasteValues
Next D
Next C
Any help greatly appreciated
cheers
You should be able to do this without using a loop, or copy/paste:
Sub Testnewname()
Dim Nw2 As Long, ws As Worksheet, wsCostTbl As Worksheet, cDest As Range
Set ws = ActiveSheet 'or some other specific sheet
Set wsCostTbl = ThisWorkbook.Worksheets("Cost Table")
'next empty cell on row 3
Set cDest = ws.Cells(3, ws.Columns.Count).End(xlToLeft).Offset(0, 1)
'starting row# for copy
Nw2 = Sheets("Cost Table").Range("$H$10").Value
'using the source range...
With ws.Range(ws.Cells(Nw2, 10), ws.Cells(Rows.Count, 10).End(xlUp))
'...transfer the values, flipping rows and columns using Transpose
cDest.Resize(.Columns.Count, .Rows.Count).Value = Application.Transpose(.Value)
End With
wsCostTbl.Range("H10").Value = wsCostTbl.Range("H11").Value
End Sub
Hi thank you both for that, I have tested both ways and work for the life of me couldn't work out the possion of the C=C+1.
Tim i really like this with out looping i did try something like this as i have another script that i removed looping from as itwas so much quiker.
With ws.Range(ws.Cells(Nw2, 10), ws.Cells(Rows.Count, 10).End(xlUp))
'...transfer the values, flipping rows and columns using Transpose
cDest.Resize(.Columns.Count, .Rows.Count).Value = Application.Transpose(.Value)
End With
Is a new one for me and will be very useful in anumber of toold i am createing thank you for this
I've a data where I applied filter to the column based on its header. Now I want to make some changes to filtered data i.e. visible cells in the same column. I've below mentioned code where filter has been applied to column with header "Query Type" & it's column letter is "E". Is it possible to put offset based on the column header instead of column letter? Because column gets changing everytime. In below example, how E2 or E can be replaced dynamically to accommodate column with header? I tried replacing "E" with FiltCol; however it is not working.
Sub Filter()
Dim FiltCol As Variant
FiltCol = Rows("1:1").Find(What:="Query Type", LookAt:=xlWhole).Column
ActiveSheet.UsedRange.AutoFilter Field:=FiltCol, Criteria1:="Rejected"
ActiveSheet.Range("E2", Range("E" & Rows.Count).End(xlUp)).SpecialCells(xlCellTypeVisible).FormulaR1C1 = "Accepted"
End Sub
When you want to deal with column numbers, you can use the .Cells-property of the worksheet. Cells expects 2 parameters, row and column. The row is always a (long) number, the column can be specified as number or with the column character(s)
The following terms are all the same:
ActiveSheet.Range("D3")
ActiveSheet.Cells(3, 4)
ActiveSheet.Cells(3, "D")
Your code could look like
Sub Filter()
Dim FiltCol As Variant
With ActiveSheet
FiltCol = .Rows("1:1").Find(What:="Query Type", LookAt:=xlWhole).Column
Dim lastRow As Long
lastRow = .Cells(.Rows.Count, FiltCol).End(xlUp).row
.UsedRange.AutoFilter Field:=FiltCol, Criteria1:="Rejected"
Dim visibleCells As Range
On Error Resume Next ' Avoid runtime error if nothing is found
Set visibleCells = .Range(.Cells(2, FiltCol), .Cells(lastRow, FiltCol)).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not visibleCells Is Nothing Then
visibleCells.Value2 = "Accepted"
End If
End With
End Sub
cells(1,1).offset(2,3)
will get you from A1 to D3
lastRow = Cells(105000, FiltCol).End(xlUp).Row <<< This is poor, see edit below
ActiveSheet.Range(Cells(2, FiltCol).Offset(0, 1), Cells(lastRow, FiltCol).Offset(0, 1)).SpecialCells(xlCellTypeVisible).FormulaR1C1 = "Accepted"
edit:
Better to dynamically describe the last row
lastRow = Cells(Cells.Rows.Count, FiltCol).End(xlUp).Row
Its been a while since I have done any sort of coding, so I am very rusty.
I am trying to write some VBA code, so that when a button is clicked in the excel sheet it will check another sheet in the same workbook and copy of specific cell values. This is based on a criteria in one of the columns (column 15, I counted); I should probably add that the data is in a table. if that row meets the specified criteria from column 15, then specific columns are copied over to the worksheet with the button.
I do have some code, but I know there is a lot missing from it.
Would appreciate some input, am I on the right track? can anyone help on there I can get more info and tips on the coding I need to use. Not sure if there is an easy way to do this using tables?
Private Sub CommandButton1_Click()
''This will count how many rows are populated in the table''
a = Worksheets("Billable").Cells(Rows.Count, 1).End(xlUp).Row
''Loop will run from row 6 to the last row (Row 6 is the first row in table)''
For i = 6 To a
''If statement which will check the status column for Detailed Estimate Submitted > column 15''
If Worksheets("Billable").Cells(i, 15).Value = "Detailed Estimate Submitted" Then
Worksheets("Billable").Rows(i).Copy
Worksheets("PM_Forecast").Activate
b = Worksheets("PM_Forecast").Cells(Rows.Count, 1).End(xlUp).Row
Worksheets("PM_Forecast").Cells(a + 1, 1).Select
ActiveSheet.Paste
End If
Next
Application.CutCopyMode = False
End Sub
An example of the table: -
I only need to copy over 3 of the columns if they meet a specific criteria in the status column
You did not answer my question regarding the format pasting...
So, please, test the next code which pastes on a classical way. But without selecting and declaring all used variables:
Private Sub CommandButton1_Click()
Dim shB As Worksheet, shPM As Worksheet, lastRowB As Long, lastRowPM As Long
Dim i As Long, lastCol As Long
Set shB = Worksheets("Billable")
Set shPM = Worksheets("PM_Forecast")
lastRowB = Worksheets("Billable").Cells(Rows.Count, 1).End(xlUp).row
'Loop will run from row 6 to the last row (Row 6 is the first row in table)''
For i = 6 To lastRowB
If shB.Cells(i, 15).Value = "Detailed Estimate Submitted" Then
lastCol = shB.Cells(i, Columns.Count).End(xlToLeft).Column
lastRowPM = shPM.Cells(Rows.Count, 1).End(xlUp).row
shB.Range(shB.Range("A" & i), shB.Cells(i, lastCol)).Copy _
shPM.Cells(lastRowPM + 1, 1)
End If
Next
Application.CutCopyMode = False
End Sub
For array using variant you must only declare a new variable Dim arr As Variant and replace this part:
shB.Range(shB.Range("A" & i), shB.Cells(i, lastCol)).Copy _
shPM.Cells(lastRowPM + 1, 1)
with this one:
arr = shB.Range(shB.Range("A" & i), shB.Cells(i, lastCol)).Value
shPM.Cells(lastRowPM + 1, 1).Resize(, UBound(arr, 2)).Value = arr
Then, delete the code line Application.CutCopyMode = False. It is not necessary, anymore, since the Clipboard memory is not used...
And use Option Explicit on top of your module. It will save you many times, when the code will become complex.
I cant comment so I will ask the question through this answer:
Your variable b is currently not being used, I think it was meant to be in this line: Worksheets("PM_Forecast").Cells(b + 1, 1).Select but you have written a instead of b.
Does this solve your current issue?
After inserting a Table into Excel, I want to change the Table Style. However, it's not changing the style.
How do I use the 'Apply and Clear Formatting' function in VBA?
For Each ws In ActiveWorkbook.Worksheets
With ws
If .Index <> 1 Then
'Insert Table with the Data starting in Column A, Row 3
Dim myTable As ListObject
Set myTable = .ListObjects.Add(xlSrcRange, .Range("A3", .Range("A3").End(xlToRight).End(xlDown)), , xlYes)
With myTable
.Name = .Name & "_Table"
.TableStyle = "TableStyleMedium12"
.Range.Font.Bold = True
.Range.Font.Size = 16
End With
In Excel, a cell is defined by its coordinates, like A3. The corresponding VBA syntax is Cells(3, "A") or better still, Cells(3, 1).
In Excel, a range is defined by its first and last cell, like A3:D12. In VBA the same is expressed like Range(Cells(3, "A"), Cells(12, "D")) or - more proficient - Range(Cells(3, 1), Cells(12, 4)). Prefer numbers to define columns because they can be calculated. Excel can find Columns(3 + 4) but it can't find Columns("C" + 4).
Cells(Rows.Count, "A") defines a single cell which is equal to Cells(1048576, 1). It's the last possible cell in column A. Similarly, Cells(3, Columns.Count) defines a cell at the extreme right of row 3. Columns.Count = 16384 but might be a smaller number in worksheets created with earlier versions of Excel.
The combination of either of the above expressions with .End(xlUp) or End.(xlToLeft) just describes an offset from the cell already defined, to look for the first occupied cell (the End), either up or To[the]Left. Therefore these expressions define a single cell. They wouldn't even define a range if they were presented as first and last cell of a range in proper syntax. This, Range("A3", .Range("A3").End(xlToRight).End(xlDown)), isn't proper syntax.
In the code below I have taken pains to take you through the process of defining the range for your table in small steps. It works, and that's great. But the point is that it should work for you, and it will only do that if you fully understand it. I hope the above explanation helps toward that end.
Sub InsertTable()
' 026
Dim Ws As Worksheet
Dim Tbl As ListObject
Dim Rng As Range ' range in which to set the table
Dim Rl As Long ' last row
Dim Cl As Long ' last column
For Each Ws In ActiveWorkbook.Worksheets
With Ws
If .Index > 1 Then
' find the last used row in column A
Rl = .Cells(.Rows.Count, "A").End(xlUp).Row
' find the last used column in row 3
Cl = .Cells(3, .Columns.Count).End(xlToLeft).Column
' set the range for the table
Set Rng = .Range(.Cells(3, "A"), .Cells(Rl, Cl))
' convert the range to a table
Set Tbl = .ListObjects.Add(xlSrcRange, Rng, , xlYes)
End If
End With
With Tbl
.Name = .Name & "_Table"
.TableStyle = "TableStyleMedium12"
.Range.Font.Bold = True
.Range.Font.Size = 16
End With
Next Ws
End Sub
I have a datasheet that is imported regularly and the length changes.
So, I want to write some VBA code that deletes any extra rows and autofills any formulas to the last row.
I have the first part done. This code finds the last row, and deletes anything below it.
Sub CleanData()
Dim lastrow As Long
Sheets("Open Operations").Select
Range(Cells(Rows.Count, 1).End(xlUp).Offset(1), _
Cells(Rows.Count, 1)).EntireRow.Delete
lastrow = ActiveSheet.UsedRange.Rows.Count
End Sub
The part I'm stuck on is that I'm not sure how to autofill any columns that need it. These columns could be changing, so I want my code to be able to handle this. So, I want to iterate over all of the cells in the first row, from the very first column to the last column in use. Then, if that cell is a formula, I want to fill the formula down to the lastrow, as defined in the first code block.
Here's what I have so far:
Dim lastcolumn As Long
lastcolumn = ws.Cells(1, Columns.Count).End(xlToLeft).Column
For Each c In ActiveSheet.Range("A1:A" & lastcolumn).Cells
If c.HasFormula = True Then
But I'm pretty new to VBA, and I'm not sure how to make the column fill down to the previously defined Last Row.
EDIT: To clarify -- I want to iterate over every first cell in each column until the last column. Then, if that cell contains a formula, I want to autofill/filldown that whole column to the lastrow defined in the first code block.
Thanks.
I've managed to create code that accomplishes the task mentioned above:
Here is the code for anyone interested:
Sub CleanData()
' Clean the data
Application.Calculation = xlManual
Call CleanSheet("Order Headers")
Call CleanSheet("Open Operations")
Call CleanSheet("Confirmations (SAP)")
Call CleanSheet("VA05")
Call CleanSheet("ZOOP")
Call CleanSheet("PremExped")
Application.Calculation = xlCalculationAutomatic
End Sub
Sub CleanSheet(SheetName As String)
' Cleans the Sheet specified by SheetName
' Variable Declaration
Dim NumColumns As Long
Dim NumRows As Long
Dim ColumnCounter As Long
' Find the number of rows and columns in SheetName
NumRows = Sheets(SheetName).Cells(Rows.Count, 1).End(xlUp).Row
NumColumns = Sheets(SheetName.Cells(1, Columns.Count).End(xlToLeft).Column
' Define the ranges for pulling down the formulas
Set rng1 = Worksheets(SheetName).Range("A2:A" & NumRows)
Set rng2 = Worksheets(SheetName).Range("A2")
' Delete extraneous rows of data
Sheets(SheetName).Select
Range(Cells(Rows.Count, 1).End(xlUp).Offset(1), _
Cells(Rows.Count, 1)).EntireRow.Delete
' Ensure all formulas are dragged down appropriately
For ColumnCounter = 0 To NumColumns
If rng2.Offset(0, ColumnCounter).HasFormula = True Then
rng1.Offset(0, ColumnCounter).FillDown
End If
Next ColumnCounter
End Sub
("A1:A" & lColumn) seems to confuse rows and columns.
I think you want:
LastRow = ActiveSheet.UsedRange.Row + ActiveSheet.UsedRange.Rows.Count - 1
or
LastRow = ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row
EDIT: Maybe just the following:
For Each c In ActiveSheet.UsedRange