Getting values from filtered excel table - excel

I am currently trying to copy all filtered values from one excel sheet to another. But it doesnt copy all visible/filtered values. Here a screenshot from my table (the other table where I paste my values is empty):
For example: When I filter the column "Ordnernummer" for the value "1/3" it copies only the following values:
This is how it should look like:
Here is the code I have so far:
Sub getCellRangeValues()
'declare Variant array to hold cell range values
Dim myValuesArray() As Variant
'declare Long to hold the last cell with data
Dim LastRow As Long
'declare variables to hold loop counters used to iterate through the individual values in the cell range
Dim rowCounter As Long
Dim columnCounter As Long
With Worksheets("Konfiguration") 'worksheet with the data
'get the last row from column a
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
'get values from all filtered rows and assign them to an array
myValuesArray = .Range("C2:I" & LastRow).SpecialCells(xlCellTypeVisible).Value
End With
ActiveWorkbook.Worksheets("GoLabel").Activate
'loop through each value in array (rows)
For rowCounter = LBound(myValuesArray, 1) To UBound(myValuesArray, 1)
'loop through each value in array (columns)
For columnCounter = LBound(myValuesArray, 2) To UBound(myValuesArray, 2)
Call setData(myValuesArray, rowCounter, columnCounter)
Next columnCounter
Next rowCounter
End Sub
Sub setData(myValuesArray() As Variant, rowCounter As Long, columnCounter As Long)
With Worksheets("GoLabel")
.Cells(rowCounter, columnCounter).Select
ActiveCell.Value = myValuesArray(rowCounter, columnCounter)
End With
End Sub

I found a workaround. Instead of saving the values in an array I just simply copy the values and paste them in my new sheet. Here the corresponding code:
'worksheet with the data
With Worksheets("Konfiguration")
'get the desired column range which is declared in the cell
startRange = "C1"
endRange = "I101"
'select values from all filtered rows
.Range(startRange & ":" & endRange).SpecialCells(xlCellTypeVisible).Select
Selection.Copy
End With
'worksheet which I fill with the copied data
ActiveWorkbook.Worksheets("GoLabel").Activate
With Worksheets("GoLabel")
.Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteValues
End With
Application.CutCopyMode = False
End Sub

Related

VBA Copy Pivot Data to next blank cell in column

A pivot table has been created and I need a macro that can pick up the Pivot body data, with no filters, from a specified worksheet (Pivot1) and copy the results into another sheet (Selection) on the next blank cell.
I've used and modified the below, which I found on this site, however its not picking up my sheets and I get a runtime error '424'
Any ideas on how this can be executed?
Sub PastePivot()
Dim i As Long
Dim LR As Long
Dim j As Long
Dim c As Long
'Find last used row in Pivot1
LR = Pivot1.Cells(Pivot1.Rows.Count, 1).End(xlUp).Row
'Find last used row in Selection
j = Selection.Cells(Selection.Rows.Count, 1).End(xlUp).Row
'Loop through rows on Pivot1
For i = 3 To LR
'Decide whether to copy the row or not
If Pivot1.Cells(i, 1).Value <> "0" Then
'Update pointer to the next unused row in Selection
j = j + 1
'Only copy used columns, to stop it thinking every cell in the
'destination row is "used"
c = Pivot1.Cells(i, Pivot1.Columns.Count).End(xlToLeft).Column
'Copy the values (without using Copy/Paste via the clipboard)
Selection.Rows(j).Resize(1, c).Value = Pivot1.Rows(i).Resize(1, c).Value
End If
Next i
End Sub
If you want to get the body of a pivot table use it's DataBodyRange property.
The below code assumes you have 1 pivot table on 'Sheet1' and you want to copy it to 'Sheet2'.
Sub CopyPivotBody()
Dim ws As Worksheet
Dim pt As PivotTable
Dim rngBody As Range
Set ws = Sheets("Sheet1")
Set pt = ws.PivotTables(1)
Set rngBody = pt.DataBodyRange
rngBody.Copy Sheets("Sheet2").Range("A" & Rows.Count).End(xlUp).Offset(1)
End Sub
Note, if that doesn't give you the exact range you want you can offset/resize it like any other range.

Need some help using setting variables to determine which cells I want to select in my range

The amount of cells in my data table changes every week so I'm using a count function to determine the number of cells with data then using that count as a variable to put into my range(cells(x,x),cells(x,x) function to select. But I'm having an issue with taking the count and converting it to a variable to use. This is a basic macro I'm putting together for something else i'm doing.
Sub format_table()
Dim x As Long
Dim y As Long
''count the number of rows in rawdata table
Dim LastRow As Integer
With ActiveSheet
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
x = LasRow
''count the number of columns in rawdata table
Dim LastCol As Integer
With ActiveSheet
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
y = LastCol
'''use the counted cells to determine a range to select
ActiveSheet.Range(Cells(1, 1), Cells(x, y)).Select
End Sub
I think you are having trouble trying to get the column number as the correct letter, right? Try something like this:
Sub Test()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Set ws = wb.Sheets("Sheet1") '(replace with whatever sheet name is)
Dim lastRow as Integer, lastCol as Integer, lastColLet as Integer
'get the number value of the last row and column
lastRow = ws.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
lastCol = ws.Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
'uncomment the debug.print statements to see what it's getting for last row/column
'Debug.Print lastRow
'Debug.Print lastCol
'get the letter that the column number corresponds to
lastColLet = Letter(lastCol)
'Debug.Print lastColLet
ws.Range("A1:" & lastColLet & lastRow).Select
End Sub
Function Letter(ByVal lngCol As Long) As String
Dim vArr
vArr = Split(Cells(1, lngCol).Address(True, False), "$")
Letter = vArr(0)
End Function
It uses the function found here: Function to convert column number to letter? in order to convert the column # to a letter, then you can concat the letter and last row to select the way you wanted.
I guess your real issue is to decide what cells you actually need to select
your approach assumes that the left-upmost data cell is always in cell(1,1) and the down-right one is in the intersection of:
last non empty row in column 1, last non empty column in row 1
should that be the case, then you can go on with your code provided you change x = LasRow to x = LastRow...
should not that be the case then you could assume that the range is the one delimited by:
first non empty row in column 1, first non empty column in row 1
last non empty row in column 1, last non empty column in row 1
then you could use this code:
Function GetData() As Range
Dim firstRow As Long, firstColumn As Long
Dim LastRow As Integer, lastColumn As Long
With ActiveSheet
firstRow = .UsedRange.Rows(1).Row '<--| get first used row index
firstColumn = .UsedRange.Columns(1).Column '<--| get first used column index
LastRow = .Cells(.Rows.Count, firstColumn).End(xlUp).Row '<--| get the first used column last non empty cell row index
lastColumn = .Cells(firstRow, .Columns.Count).End(xlToLeft).Column '<--| get the first used rows last non empty cell column index
'return the range
Set GetData = .Range(Cells(firstRow, firstColumn), Cells(LastRow, lastColumn))
End With
End Function
and exploit it in your main code as follows:
Sub format_table()
With GetData '<-- use With-End With block to reference wanted object (Range) and avoid Select/Selection/Activate/ActiveXXX
'format the referenced range
.Font.Name=..
.Interior.Color=..
End With
End Sub
but the GetData() function may still be not the one you need, should data be "jagged" in columns and or/rows with first row/column not hosting the last column/cell
so maybe you simply need:
Sub format_table()
With ActiveSheet.UsedRange
'format the referenced range
' .Font.Name=..
' .Interior.Color=..
End With
End Sub

Autofilter array criteria [duplicate]

My intention was to have the following code compile data from my "Low CPM 1" worksheet into an array and then filter my active worksheet based on this array. While the macro does seem to affect the filters, none of the values get filtered out. Any help on this matter would be greatly appreciated
Sub Macro1()
Dim CPM1Array(0 To 300) As Variant
For i = 2 To UBound(CPM1Array)
CPM1Array(i) = Sheets("Low CPM 1").Cells(i, 2).Value
Next i
ActiveSheet.Range("$A$1:$H$251").AutoFilter Field:=3, Criteria1:=("<>1 to Ubound(CPM1Array)"), Operator:=xlFilterValues
End Sub
There is no simple way with autofilter to achieve what you want. You cannot use Criteria1:="<>MyArray"
Alternative
We know which values we do not want. We can find out what are the values of the relevant column
Simply store the values of the relevant column in an array and then remove the unnecessary values from it by comparing it with the array which has values we do not want.
Remove blank cells from the array
Pass the final array to the autofilter.
In Action
Let's say our worksheet looks like as shown in the below image. I am taking an example of only 15 rows.
Code
Sub Sample()
Dim ws As Worksheet
Dim MyAr(1 To 5) As String
Dim tmpAr As Variant, ArFinal() As String
Dim LRow As Long
ReDim ArFinal(0 To 0)
Set ws = ActiveSheet
'~~> Creating an array of values which we do not want
For i = 1 To 5
MyAr(i) = i
Next i
With ws
'~~> Last Row of Col C sice you will filter on 3rd column
LRow = .Range("C" & .Rows.Count).End(xlUp).Row
'~~> Storing the values form C in the array
tmpAr = .Range("C2:C" & LRow).Value
'~~> Compare and remove values which we do not want
For i = 1 To LRow - 1
For j = 1 To UBound(MyAr)
If tmpAr(i, 1) = MyAr(j) Then tmpAr(i, 1) = ""
Next j
Next i
'~~> Remove blank cells from the array by copying them to a new array
For i = LBound(tmpAr) To UBound(tmpAr)
If tmpAr(i, 1) <> "" Then
ArFinal(UBound(ArFinal)) = tmpAr(i, 1)
ReDim Preserve ArFinal(0 To UBound(ArFinal) + 1)
End If
Next i
'~~> Filter on values which you want. Change range as applicable
.Range("$A$1:$H$15").AutoFilter Field:=3, Criteria1:=ArFinal, Operator:=xlFilterValues
End With
End Sub
Output

VBA- How to copy and paste values to another sheet beginning on next available row

I have a vba code that copies rows on a sheet to another sheet depending if column A = 1 and it works perfectly. I am trying to make it paste to the next available row instead of overwriting the data that is already there in order to make a log. Here is the code I have already but I can't seem to figure out how to make it paste to the next available row. Any help would be greatly appreciated! Thanks in advance!
Sub Log()
Dim rng As Range
Dim lastRow As Long
Dim cell As Variant
Dim count As Long
count = 0
With ActiveSheet
lastRow = .Range("A" & .Rows.count).End(xlUp).Row
Set rng = .Range("A3:A" & lastRow)
For Each cell In rng
If cell.Value = "1" Then
Range(cell.Offset(0, 1), cell.Offset(0, 6)).Copy
Range("'Log'!B3").Offset(count, 0).PasteSpecial xlPasteValues
count = count + 1
End If
Next
End With
End Sub
You just need to loop through the source sheet.
Try using .Cells(row,col) instead of Range..
This example is heavy on the comments to help understand the looping process.
You will need a few additional Functions to make this work using this code.
LastRow Function
Function lastRow(sheet As String) As Long
lastRow = Sheets(sheet).Cells(Rows.Count, "A").End(xlUp).Row 'Using Cells()
End Function
LastCol Function
Function lastCol(sheet As String) As Long
lastCol = Sheets(sheet).Cells(2, Columns.Count).End(xlToLeft).Column
End Function
Code for solution: Assuming you have your target sheet's headers already set up AND the target and source sheet share the same formatting.
Sub Log()
Dim source As String, target As String
Dim sRow As Long, col As Long, tRow As Long
'Declare Sheets
source = "Sheet1"
target = "Sheet2"
'Loop through rows of source sheet
For sRow = 2 To lastRow(source)
'Get current last row of Target Sheet
tRow = lastRow(target) + 1
'Meet criteria for Column A to = 1 on Source
If Sheets(source).Cells(sRow, 1) = "1" Then
'Copy each column of source sheet to target sheet in same order
For col = 1 To lastCol(source)
Sheets(target).Cells(tRow, col) = Sheets(source).Cells(sRow, col)
Next col
End If
Next sRow
End Sub

Copy rows in Excel if cell contains name from an array

I have an Excel sheet that contains entries for ~150 employees. Each row contains the name as well as hours worked, pay, team, etc etc etc etc. The B column in each row contains the employees name in Last,First format. About half the employees on the sheet are part time employees. What i'm trying to do is write a macro in VB that copies the entire row if the name in the B column matches one of the names of the part time employees so that one of my coworkers can simply run the macro and paste all of the rows of copied users into a new sheet each week. Here's what I currently have. (I have all of the employees names in the array however I have censored them out) I really don't understand much of the last 50% of the code. This stuff was stuff I found online and have been messing around with.
`Sub PartTime()
Dim strArray As Variant
Dim wsSource As Worksheet
Dim wsDest As Worksheet
Dim NoRows As Long
Dim DestNoRows As Long
Dim I As Long
Dim J As Integer
Dim rngCells As Range
Dim rngFind As Range
Dim Found As Boolean
nameArray = Array(NAMES CENSORED)
Set wsSource = ActiveSheet
NoRows = wsSource.Range("A65536").End(xlUp).Row
DestNoRows = 1
Set wsDest = ActiveWorkbook.Worksheets.Add
For I = 1 To NoRows
Set rngCells = wsSource.Range("C" & I & ":F" & I)
Found = False
For J = 0 To UBound(strArray)
Found = Found Or Not (rngCells.Find(strArray(J)) Is Nothing)
Next J
If Found Then
rngCells.EntireRow.Copy wsDest.Range("A" & DestNoRows)
DestNoRows = DestNoRows + 1
End If
Next I
End Sub`
This code should work for what you are looking for. It is important to note that the string names in your array must be identical to that in Column B (with the exception of leading and trailing spaces), so if the names are written "LastName, FirstName" then your input data must be identical. This code could be tweaked to not have this requirement, but for now I've left it as such. Let me know if you'd prefer the code be adjusted.
Option Explicit
Sub PartTimeEmployees()
Dim NewSheet As Worksheet, CurrentSheet As Worksheet, NameArray As Variant
Set CurrentSheet = ActiveWorkbook.ActiveSheet
Set NewSheet = Sheets.Add(After:=Sheets(Worksheets.Count))
NewSheet.Name = "Part Time Employees"
NameArray = Array("NAMES CENSORED")
'Pulling headers from the first row
CurrentSheet.Rows(1).EntireRow.Copy
NewSheet.Select 'Redundant but helps avoid the occasional error
NewSheet.Cells(1, 1).Select
ActiveSheet.Paste
CurrentSheet.Select
Dim NextRow As Long
NextRow = 2
'Writing this code to not assume that the data is continuous
Dim Count As Long
'Iterating to the end of the data in the sheet
For Count = 2 To CurrentSheet.UsedRange.Rows.Count
If Not IsEmpty(CurrentSheet.Cells(Count, 2)) Then
For Counter = 1 To UBound(NameArray)
'Performing string operations on the text will be faster than the find method
'It is also essential that the names are entered identically in your array
If UCase(Trim(CurrentSheet.Cells(Count, 2).Value)) = UCase(NameArray(Counter)) Then
CurrentSheet.Rows(Count).Copy
NewSheet.Select
NewSheet.Cells(NextRow, 1).Select
ActiveSheet.Paste
CurrentSheet.Select
NextRow = NextRow + 1
Exit For
End If
Next Counter
End If
Next Count
End Sub
No need to loop through the array if you use a Range.AutoFilter Method with the array as criteria.
See comment for each line of operational code.
Option Explicit
Sub partTimers()
Dim nameArray As Variant
'construct an array of the part-time employees' names
nameArray = Array("Trgh, Evtfk", "Mtre, Sdnrm", _
"Sfgd, Pxduj", "Lsds, Qwrml", _
"Eqrd, Oqtts")
With Worksheets("Sheet1") 'you should know what worksheet the names are on
'turn off AutoFilter is there is one already in operation
If .AutoFilterMode Then .AutoFilterMode = False
'use the 'island' of cells radiating out from A1
With .Cells(1, 1).CurrentRegion
'apply AutoFilter using array of names as criteria
.AutoFilter field:=2, Criteria1:=nameArray, Operator:=xlFilterValues
'check if there is anything to copy
If Application.Subtotal(103, .Columns(2)) > 1 Then
'copy the filtered range
.Cells.Copy
'create a new worksheet
With .Parent.Parent.Worksheets.Add(After:=Sheets(Sheets.Count))
'paste the filtered range, column widths and cell formats
.Cells(1, 1).PasteSpecial Paste:=xlPasteColumnWidths
.Cells(1, 1).PasteSpecial Paste:=xlPasteFormats
.Cells(1, 1).PasteSpecial Paste:=xlPasteValues
End With
End If
End With
'turn off the AutoFilter
If .AutoFilterMode Then .AutoFilterMode = False
'turn off active copy range
Application.CutCopyMode = False
End With
End Sub

Resources