Issue with nested for loops in VBA - excel

I'm working on a project in Excel that helps a club here on campus allocate money to various other clubs. Anyways, I'm attempting to implement a macro-assigned button to allow the club to generate a new sheet that summarizes the event name, and the funding granted to the event.
The issue I'm currently stuck on is assigning 12 rows of data on this new sheet, for each club listed in the 'Summary' tab. I have the formula so that it cycles through the summary tab and inputs the club name down, but it continually inputs these names into cells A1-A12, rather than adding 12 new rows for the next club.
If my wording is confusing to follow; I want club 1's data to be in cells A1-12, club 2 in A13-24, etc.
I'm relying on nested for loops to try and cycle through and create these rows. Here's the part that's giving me trouble:
For k = 0 To 200 Step 12
'J is used to get names off the 'summary' tab
For j = 8 To Sheets.Count
'I is used to select cells 'a1' to 'a12'
For i = 1 To 12
Range("A" & (k + i)).Select
ActiveCell.Formula = ("=Summary!$A$" & j)
Next i
Next j
Next k
I'm certain my problem lies in the fact that j is advanced further before k, meaning it will continue to see k as 0 and input the new club's name in a1-a12, rather than stepping it up 12 BEFORE j is advanced. Whenever I try to insert next k above next j, I'm given an error.
This nested for loop is messy and is starting to make my brain hurt- but I can't seem to figure out a better way to tell Excel to skip 12 rows at a time. If anyone has any input or ideas on how to execute this macro in an easier way- let me know :-)

Try this code. There is no need to select cell before writing formula in it...
For j = 8 To Sheets.Count
For i = 1 To 12
Range("A" & ((j - 8) * 12 + i)).Formula = ("=Summary!$A$" & j)
Next i
Next j

Related

Checking if each number in a list is between multiple ranges

I have a list of numbers (that will be changed weekly) and I also have a list of ranges (that also change weekly). I need to check whether each number falls between each range.
Eg. My list of numbers on the left and my list of ranges on the right.
4 1 3
10 67 99
54 120 122
155
So what I need is to return a value if 4 falls between 1-3, then check if it falls between 67-99 and so on. Then return a value if 10 falls between 1-3 or 67-99 etc.
I have tried array and vba but I'm noob and I cant find much in the way of examples for this issue. I have had success with the following nested if;
=IF(OR(AND(G2>$L$2,G2<$M$2),AND(G2>$L$3,G2<$M$3),AND(G2>$L$4,G2<$M$4),G2,"")
=IF(OR(AND(G3>$L$2,G3<$M$2),AND(G3>$L$3,G3<$M$3),AND(G3>$L$4,G3<$M$4),G3,"")
However, once my number of ranges gets above a certain number it says i have too many characters.
Any help would be appreciated.
Regards,
Will.
So what I need is to return a value if 4 falls between 1-3, then check if it falls between 67-99 and so on. Then return a value if 10 falls between 1-3 or 67-99 etc.
If you want to match each value in col G with the list in L and M then, rearrange the G column values in a row as shown below so that you can get the entire view in one go.
Put this formula =(AND($N$1>L2,$N$1<M2)) in N2 and drag it down. Similarly put the formula =(AND($O$1>L2,$O$1<M2)) in O2 and pull it down and so on...
Thanks Siddarth. This works but the number of rows will be changing weekly and your method would be too tedious to do weekly.
Ended up working it out on my own. Pretty simple but took me forever!
Sub Subtract_Start()
Set rng1 = Range(Range("G2"), Range("G2").End(xlDown))
Set rng2 = Range(Range("L2"), Range("L2").End(xlDown))
For i = 2 To rng1.Rows.count
For j = 2 To rng2.Rows.count
If Cells(i, "G").Value > Cells(j, "L").Value Then
If Cells(i, "G").Value < Cells(j, "M").Value Then
Cells(i, "G").Copy Cells(i, "J")
End If
End If
Next j
Next i
End Sub

Spacing One Picture per Page

I am currently having to attach many pictures (jpeg) to an excel document and exporting it as a pdf. I need one picture per page.
I was using the following code, but with no avail.
For j = 0 To i
Cells(2, 1).Activate
Let pm = "Q:\Public\ACCE LINEAR\IRAD Photomics\A 350 Frame Photomics " & dat & "\" & sn & "\PHOTOMICS" & j & ".jpg"
ws1.Pictures.Insert(pm).Select
incr = 660 * (j + 1)
Selection.ShapeRange.IncrementTop incr
Next j
I activate Cell A2 so that the picture will initially be placed in the same spot every time. I then move the picture down a certain amount as defined by the variable "incr". At first I toyed with that number (660) until it worked and then went on to the next report. The problem is that what works for one report doesn't work for another.
I find this surprising as I have my print area (I believe that dictates the length of a page) set to incorporate all columns. Although each report has a unique amount of rows, they each have exactly the same amount of columns. Therefore, the print area should be the same from sheet to sheet and each picture is exactly the same size so that number shouldn't have to change from report to report.
I still don't understand why my previous spacing idea didn't work when the print area from sheet to sheet is exactly the same. However, knowing the print area is the same I instead made the top left cell in each page active and inserted each picture into that cell. This ensured that the pictures did not get cut when the excel file was exported as a PDF.
Here is the code I used. There are a few variable that were defined earlier in the code, but you should get the idea
b = counter - 1
For j = 0 To b
a = j + 1
If i > 24 Then a = j + 2
incr = (42 * a) - j
Cells(incr, 1).Activate
ws1.Pictures.Insert(MyFolder & "\" & PMArray(j)).Select
Next j

Macro to Group Rows Throughout Excel Document

I have looked around and I feel like I am going crazy for not understanding how to do this, or what to do. It seems simple and yet I cannot figure out the best method.
I have an excel document that has 8 rows of data and that is supported by individual data from individuals that is 16 rows long. In total, there are 600 individuals in the dataset.
I was trying to locate a macro that would simply allow me to group every 16 rows in my excel sheet together. Whatever I have tried though, has not worked.
I am using Microsoft Excel 20116 for mac.
Range("1:16").Select
Selection.Rows.Group
Range("17:32").Select
Selection.Rows.Group
Repeat!
If there is a predictable data pattern (i.e. always exactly 16 rows) you might wish to put this inside a loop, where Range.Select is offset a further 16 rows each time.
For example:
i = 1
j = 16
While i < "YOUR UPPER LIMIT"
Range(i & ":" & j).Select
Selection.Rows.Group
i = i+16
j = j+16
Next
Note that if you group contiguous rows without a break, your groupings will automatically combine. You will need to play around with the line Range(i & ":" & j).Select to either use i+1 or j-1 depending on what you want as your display row on the grouping.

Retaining original table formatting after a 'pagebreak'

So here's the finished product, a statement of accounts with a working statement table, and an ageing analysis:
Everything works great. It basically populates itself row by row with data from another table. Here is the sample code:
j = 21 'First row on the statement of accounts workbook
For k = 1 To TSOA.ListRows.Count 'TSOA is the original data table
If Not TSOA.DataBodyRange.Rows(k).Hidden Then 'excludes the filtered entries
SOAwb.Worksheets(1).Cells(j, 4) = TSOA.DataBodyRange(k, 6) 'Debit
SOAwb.Worksheets(1).Cells(j, 5) = TSOA.DataBodyRange(k, 7) 'Credit
SOAwb.Worksheets(1).Cells(j, 1) = TSOA.DataBodyRange(k, 3) 'Date
<some other similar code goes here>
j = j + 1 'forces next row
If (j + 4) Mod 50 = 0 Then 'Increase footer, since there are only 50 rows in a page
j = j + 12 'Increase header
End If
End If
Next
So I coded in a 'somewhat' dynamic pagebreak, using the line of code:
If (j + 4) Mod 50 = 0 Then
j = j + 12 'Increase header
End If
where (j + 4) is the trigger for the footer pagebreak, Mod 50 divides (j+4) by 50 and gives you the remainder. Hence if its perfectly divisible, the result = 0.
j + 12 helps to skip past the header logos, you'll understand why in the next picture.
So the line of code basically works if you didn't care about the subsequent table formatting: ><
So does anyone know how do I continue with the previous table's formatting, ie the green and white statement table in the original page in the second page? Or is there some way to preload the table formatting in the second page (bearing in mind that not all statements need a second page). Or perhaps even tinkering about the print settings when the pagebreak triggers? Or any other creative solutions?
I have had zero experience with dealing with multiple pages using VBA, and quite frankly, I do not even know how to go about navigating between pages. I can't stress hard enough that this code is my amateur attempt to do useful things with excel, so there must be room for improvement!
Just change the page margins and the top few rows get excluded, but the manual page break is still required though!

Get maximum value of columns in Excel with macro

First of all I have no idea of writing macros in excel, but now I have to write a code for a friend. So here we go.
In my excel sheet I have a table which holds some producers as columns and 12 months of the year as rows. In their intersecting cell it's written the amount of products produced by the producer during that month. Now I need to find maximum and minimum values of produced goods within each month and output the producers of that goods.
I found a code for a similar problem, but I don't understand it clearly and it has errors.
Here is the code:
Sub my()
Dim Rng As Range, Dn As Range, Mx As Double, Col As String
Set Rng = Range(Range("A1"), Range("A6").End(xlUp))
ReDim ray(1 To Rng.Count)
For Each Dn In Rng
Mx = Application.Max(Dn)
Select Case Mx
Case Is = Dn.Offset(, 0): Col = "A"
Case Is = Dn.Offset(, 1): Col = "B"
Case Is = Dn.Offset(, 2): Col = "C"
Case Is = Dn.Offset(, 3): Col = "D"
End Select
ray(Dn.Row - 1) = Col
Next Dn
Sheets("Sheet2").Range("A2").Resize(Rng.Count) = Application.Transpose(ray)
End Sub
I get the following error:
Run-time error'9': Subscript out of range.
So my question is, what does this error mean and what do I need to change in this code to work?
EDIT1:
OK, now the error is gone. But where do I get the results?
EDIT2
I know this line is responsible for inserting the results in specified place, but I cant see them after execution. What's wrong with that?
Error means the array you are trying to access has not been defined to contain the ordinal you're looking for: For example Array 10 has positions 0-9 so if I try and access array(10) it would throw that error or array(-1) it would throw that error.
I can't remember if excel is 0 or 1 based arrays.
Possibly change
ray(Dn.Row - 1) = Col
to
if dn.row-1<> 0 then ' or set it to <0 if zero based.
ray(Dn.Row - 1) = Col
end if
You don't need VBA (a macro) to do this. It can be done using a worksheet formula.
E.g.
If your producers are P1,P2,P3,P4 and your sheet looks like this:-
A B C D E F
+-------------------------------------------
1 | Month P1 P2 P3 P4 Top Producer
2 | Jan 5 4 3 2
3 | Feb 2 3 5 1
4 | Mar 6 4 4 3
...
...
The following formula placed in cells F2,F3,F4,... will pick out the top producer in each month.
=INDEX($B$1:$E$1,MATCH(MAX(B2:E2),B2:E2,0))
Generally it's better to try and use built in Excel functionality where possible. Resort to VBA only if you really need to. Even if you were to use the top producer/month data for some other operation which is only possible in VBA, at least the top producer/month data derivation is done for you by the worksheet, which will simplify the VBA required for the whole process.
Transposing a range can also be done using a worksheet formula by using the TRANSPOSE() function.
BTW - I'm not sure what you want to do if two producers have the same output value. In the VBA example in your question, the logic seems to be:- if two producers are joint top in a month, pick the first one encountered. The formula I've given above should replicate this logic.
I have used these functions quite extensively and they are very reliable and fast:
Public Function CountRows(ByRef r As Range) As Integer
CountRows = r.Worksheet.Range(r, r.End(xlDown)).Rows.Count
End Function
Public Function CountColumns(ByRef r As Range) As Integer
CountColumns = r.Worksheet.Range(r.End(xlToRight), r).Columns.Count
End Function
Give it a reference (ex. "A2") and it will return the filled cells down, or the the right until and empty cell is found.
To select multiple sells I usually do something like
Set r = Range("A2")
N = CountRows(r)
Set r = r.Resize(N,1)

Resources