Excel, cycle through columns and rows - vba

I have an excel table that calculates how many materials we need to order per job we are doing.
What I want to accomplish is to create a button that will copy the existing table on to page 2 of my excel workbook. The table is two columns wide. Therefore I would like to click the button, it copies the table thats on A and B of page 1 onto page 2 A and B. After having done so, I want excel to remember A and B are taken and next time I click the button, it goes in column C and D, then E and F and so on (always on page 2).
to explain why I would like this, I need to order 1000 sq ft of materials, but in sections. only 250 sq ft of materials at a time. So, I want to fill out how much im ordering, click the button and it saves the information of what was ordered on page 2. That way its easy to go back and see what was done, what date, how much was ordered, what is left to order, etc.
I know with numbers it would be easy by just incrementing i by two at every button click, but I dont know how to go about doing this for the excel columns (letters).
Is there some easy command I just cannot find online to do this sort of thing ?
Thanks for your help !

What you should learn in VBA and modify in this code below is how to determine the actual range of the table on Sheet1 -- instead of hard-coding it to "A1:B10"
UPDATE
Not sure why the previous version didn't work for you, but I've updated the code below to store the next column location in a helper cell to see if that works for you.
Option Explicit
Sub Button1_Click()
Dim srcTable As Range
Dim dstTable As Range
Dim nextLoc As Range
Set srcTable = Sheets("Sheet1").Range("A1:B10")
Set nextLoc = Sheets("Sheet2").Range("A20")
'--- if this is your first copy, then cell A1 should be empty
If IsEmpty(Sheets("Sheet2").Range("A1").Value) Then
Set dstTable = Sheets("Sheet2").Range("A1:B10")
nextLoc.Value = 3 'next location is column 3
Else
'--- we're adding the next table...
Set dstTable = Sheets("Sheet2").Cells(1, nextLoc.Value)
nextLoc.Value = nextLoc.Value + 2
End If
srcTable.Copy dstTable
End Sub

Related

Need to copy/paste row (x number of times) when cell value equals X

I'm trying to use Excel for a Jewelry Order Form.
In the order form (sheet1), a user may select from a cell that is formatted into a drop-down list, a number representing the number of stones in a piece of jewelry. For example, if there are 10 stones in a ring, then the user selects 10 from the drop-down list.
The details for each of the 10 stones needs to be captured in the order form (Sheet1). For example, each stone will have 4 data elements... a stone type, weight, color, cut... So I created the desired formatted row of data (in Sheet2) where each cell is a drop-down for a user to select from.
I want to create a control button to do the following actions:
Delete rows 19:150 in Sheet1
This will clear out any prior stone details that may be displayed.
Find the value in cell C13 in Sheet1
This value will be used to determine how many rows should be pasted/displayed
Copy row, range A2: D2 in Sheet2
This is template row data where each cell in the row is its own drop-down list.
Paste row in B19 in Sheet1
This is the template row pasted into an order form.
4a) Paste as many rows as the value in step (2) above.
For example, if the value in step 2 from above is "3", then the stone details row will need to be pasted 3 times in the order form.
The furthest I've been able to get is the creation of the control button, and the delete clause...
Private Sub CommandButton1_Click()
Sub deleteMultipleRows()
Rows("19:150").Delete
End Sub
For the delete statement, you should probably use Sheet1.Rows("19:150").Delete as that will ensure that excel knows which sheet to delete those rows from.
You can declare a variable and assign it a value like so:
Dim rowCount as Integer
rowCount = Sheet1.Range("C13")
If you try recording a macro for the copy and pasting, you should see some sample code.
Note:
If the result looks something like this:
Sheet1.Activate
Row(2).Select
Selection.Copy
You can combine such statements like so:
Sheet1.Row(2).Copy
Since most .Activate commands can be ignored, and .Select and Selection. commands can be combined (and should be in most situations). The Sheet1. added before the .Row(2) tells Excel to specifically use Row 2 from Sheet1. Without the qualifier, i.e. just Row(2), Excel would use Row 2 from whichever sheet happens to be currently active.
You can then use a variable and the value from the sheet to loop through either pasting or copy/paste combo like so:
Dim counter as integer
For counter = 1 to Sheet1.Range("C13")
'Add code for copy/paste here
Next counter
Or if you have the rowCount variable declared and assigned, you could use it here like this:
Dim counter as integer
For counter = 1 to rowCount
'Add code for copy/paste here
Next counter

Extract Top 10 products from a Excel Database (Multiple criteria)

I have a database (example attached) that gets updated automatically from other 70 files on monthly bases by macro.
I would like to extract Top 10 ordered products based on various criteria.(example attached) The file will be more complex, just tried to keep it simple for demo.
I have used some formula =LARGE('Part numbers'!A3:A301,ROW(INDIRECT("1:"&ROWS('Part numbers'!A3:A301)))) & =SUMPRODUCT((Combine!B1:B10000='DATA '!Y3)*(Combine!C1:AB1=A1)*(Combine!D1:D10000=AC2),Combine!C1:AB10000)that aloud me tho get the SUM of top5 products the problem is when I use the INDEX MATCH to extract the name of the product if there are 2 same values the formula is stooping always at the first product name + I need to add a new criteria witch is the month
Thank you in advance for any suggestions
Its ok if it is macro or formula
.
Trying fixing the range by making reference using the INDIRECT-function:
=SUMPRODUCT((INDIRECT("Combine!$B$1:$B$5000")='DATA '!Y3)*(Combine!$C$1:$AB$1=$C$1)*(INDIRECT("Combine!$D$1:$D$5000")=$AC$2),INDIRECT("Combine!$C$1:$AB$5000"))
This ensures that the Range you are referencing, e.g. $B$1:$B$5000 doesn't become $B$1:$B$4999 when for example Row 2 is deleted.
maybe the pivot-table can help u?
there some autofilters to show the top x
if u want to set a dynamic filter on pivot table u can use this:
Sub UpdateFilter()
Dim m As String
m = Month(Now())
[filPivot] = m
End Sub
Issue solved more less.
The other problem that I have now is with the formula =SUMPRODUCT((Combine!$B$1:$B$5000='DATA '!Y3)*(Combine!$C$1:$AB$1=$C$1)*(Combine!$D$1:$D$5000=$AC$2),Combine!$C$1:$AB$5000) initially I have the range of the formula =5000 but every time when my database is updated this number is decreasing till it reaches =10.
My database is updated by a macro that deletes Blanks every time,I believe this could be the issue.
Any ideas how to make this =5000 range steady?

Select only one column even if a merged range lies below

Test case:
Take an empty sheet, and merge the range "D2:F2". You can do this manually.
Then, activate the macro recorder and select the column E by just clicking on the E letter on the top of the spreadsheet. You will get the following:
Columns("E:E").Select
Now, try to run this line of code from the same macro directly: you will see that it selects the three columns D, E and F.
Question:
Is this a bug of the macro recorder? Or, rather, a bug of VBA itself (that detects the merged range in my column and decides to extend the selection even if explicitly asked to select one single column)? How should I do to select only one of the columns on which a merged range lies via VBA code, exactly as I can do manually?
Need:
I have a spreadsheet with year on a line, months on the below line and days on the below line.
Hence, the days are just cells but months and especially years are shared/merged cells among the several days.
My need is just to detect the current day and select the column, in order for the user to see on which day they should look the data at. But, because of the "years" cell widely merged just above, the entire year is selected.
No, this is not a bug.
Why: Try to manually select the range E1 to E5. That is what is going on when you use Columns("E:E").select. Think of it as .Select not selecting the column, but instead selecting each cell from top to bottom.
The .select method isn't something you should depend on. What exactly are you trying to use select for? There is another (quite arguably better way) to do this.
Edit: Also, as my father always says, merged cells shouldn't be used. He uses "center across selection" instead, which looks exactly like a merged cell without any of the seemingly buggy behavior.
Need: I would use the macro to highlight the data... probably with something like this...
Range("E7").Interior.ColorIndex = RGB(0, 0, 0)
I feel that the question is genuine unlike some of the comments here. I will try to explain.
Using the test case from the question, say I want to do some action only on column D (say change its column width), without changing the same for columns E to F. I can do that in excel by selecting column D specifically by pressing on column header (press on that "D" in the column names bar). If we select column using range selection (mouse or keyboard shortcut CTRL+SPACE), it extends the selection to include E and F columns. But if we press that column D on the header, it only selects one column. I expect VBA to do the same.
Sadly, I couldn't find anything to "select" a single column or range which includes cells merging through multiple columns or range. However, I could do the action on that single column.
I tried following that didn't work. And I feel that it should work.
Range("D:D").Select
Didn't work. Extends the selection to include merged cells. I guess, this is okay.
Columns("D").Select
Didn't work. Extends the selection to include merged cells. I feel this is not okay.
Columns("D").EntireColumn.Select
Even this didn't work. This definitely should've.
So finally I directly applied the action without selecting the cells.
Column("D").ColumnWidth = 10
And this did it. Only the column D width was changed, leaving column E and F untouched. Similarly, I could do font change and other actions.
Only drawback is that I have to do all actions individually. So, I use a loop to perform action on the selection.
Something like this:
For Each x in Range("D:D")
x.font.size = 10
x.font.name = "Calibri"
'...and so on...
Next x
You probably know the row in which the days start. Therefore, instead of selecting the entire column, you could define a range starting from the first day row to the last day row and select that range.
REQUIREMENTS:
Your table should have this values and formats
Then you can loop through each column on row 4 -just assumed- and check each value if they match today. Next you can scroll to that cell using Application.Goto.
CODE:
Sub FindToday()
Dim wsTable As Worksheet '<~ worksheet with your table
Set wsTable = Sheet2
Dim Cols As Integer '<~ a variable to loop through columns
With wsTable
For Cols = 1 To .Cells(4, .Cells.Columns.Count).End(xlToLeft).Column + 1
If .Cells(4, Cols).Value = Date Then '<~ check if the date is today
Application.Goto wsTable.Cells(1, Cols), True '<~ scroll to that cell if true
Exit For
End If
Next
End With
End Sub
If you want just to hide the particular column if there is merged cell try not to select the column just use like this for example -- Columns("N").EntireColumn.Hidden = True... This will solve your doubt.

Insert new rows and populate

I need help creating a excel macro to split orders based on qty column.
In the before sheet we have 4 orders with two of them having a qty greater the 1. see before macro image
What I need is an excel macro that can check the qty field and insert new rows below based on qty value if greater then 1, then populate these rows with the data from the original row.
Then the last step would be to delete the C column. See After Macro image
I have never used macros before, so i'm not even sure if this can be done.
It's only 10 lines of code. SO is not a code sweatshop where we do the work for you, it is one where we help you work it out for yourself.
This will poll the rows for you going backwards:
For X = Range("A" & Rows.Count).End(xlUp).Row To 1 Step -1
This is key because you will be inserting rows, going forwards creates all sort of nastiness.
You will then need a loop inside there using your qty as a reference. Here is one I built but you will need to make some changes for it to work for your columns:
For Y = 1 To Range("B" & X).Value - 1
Then you need to copy row X inside this loop
Next line will be an insert with a shift down (like this Insert Shift:=xlDown) on row X + 1 or on an offset of row X by 1 row, your choice how you do this.
Last thing to do is delete column C, This can be done like this Range("C1").EntireColumn.Delete
That is it, the whole macro, just drop a couple of nexts and an end sub and run it.
You will need to Dim X and Y, dim them as longs.
Have a go, if you get stuck post back with the code you have put together and we can help you fix it.

Create VBA to autoassign type

I am a beginner in VBA programming.
Description: The left table is the 'reference table'
Objective: Fill up the 'Type' col of right table using macro
How: Write a macro that go through the 'reference table' comparing col E (Descript) with keyword. If the cell in col E contain a specific key word, col F will automatically be assigned a category
P.S: What are the recommended websites that provide tutorial? Something like codecademy
So still stuck at correctly referencing table:
thanks for editing your answer to include the code. Next time please copy/paste it, rather than using an image, so that we don't have to type it all out ourselves if we need to test what you've written! I can see where you're at now, and I feel this will work you for. Basically, you need to cycle through the rows rather than the columns.
Rather than using a subroutine, I think a function will work better for you. That way you can embed it in your table, rather than having to run a subroutine each time.
Function getCategory(strInput As String)
Dim tbl As ListObject
Dim x As Long
Set tbl = ActiveSheet.ListObjects("Table1")
For x = 1 To tbl.ListRows.Count
If InStr(strInput, tbl.ListRows(x).Range(x, 1)) Then
getCategory = tbl.ListRows(x).Range(x, 2)
Exit Function
End If
Next x
End Function
Then you can simply enter the formula in column F, e.g. in F2 enter
=getCategory(E2)
and copy/paste down for each row in your table.