I download a data set that always has a different number of rows. I store two columns as variables, the imports and the months. Then I need to run a Sumif formula that sums the value of imports by the months. I am writing a Sumif formula that uses the two variables and references the cell to its left.
The cells however vary in location based on the changing size of the data set. So I write a code to select the last active cell on a column and select the cell 3 rows down.
When writing the formula with the variables and the cell its giving me an error. Please help sorry for any typos fist time doing this.
I select all the active cells in range D and store them as months, I do the same for the imports. Then using range I find the last active cell on column M, and use select the cell 3 rows down, where I wish to write my formula.
Please see my codes to see what am I doing wrong, I am a novice coder.
Sub Importaciones()
'
' Importaciones Macro
'
Dim LastRow As Long
LastRow = Range("L" & Rows.Count).End(xlUp).Row
Dim Months As Long
Months = Range("D2", Range("D2").End(xlDown)).Select
Dim Imports As Long
Imports = Range("M2", Range("M2").End(xlDown)).Select
Dim LastRowM As Long
LastRowM = Range("M" & Rows.Count).End(xlUp).Row
Range("M" & LastRowM + 3).Formula = "=sumif(" & Months & ", " &
Range("L" & LastRow + 3) & ", " & Imports & ")"
End Sub
For the formula to work and the sum of the month that I choose comes up
As per all the comments:
Sub Importaciones()
With Worksheets("Sheet1") 'Change to your sheet
Dim LastRow As Long
LastRow = .Range("L" & .Rows.Count).End(xlUp).Row
Dim Months As Range
Set Months = .Range("D2", .Range("D2").End(xlDown))
Dim Imports As Range
Set Imports = .Range("M2", .Range("M2").End(xlDown))
Dim LastRowM As Long
LastRowM = .Range("M" & .Rows.Count).End(xlUp).Row
.Range("M" & LastRowM + 3).Formula = "=sumif(" & Months.Address(0, 0) & ", " & .Range("L" & LastRow + 3).Address(0, 0) & ", " & Imports.Address(0, 0) & ")"
End With
End Sub
Related
I'm not sure how descriptive my title is but below I will try to explain what I am trying to do.
I have a list of company Bloomberg tickers => maybe more than 100
This list of tickers is saved in say "Sheet1" "A:A"
For each ticker I have a Bloomberg (BDS) formula that returns a certain number of shareholders
The number of shareholders needs to be dynamic
The ticker of each company needs to be copied alongside the info gathered from BBG (as this is not provided by their formula)
This whole data should be in a new sheet let's say "Sheet2"
Below is the code I am using. It actually does what I need, however I am not able to make the output of my FOR loop to be in a new sheet. I also believe that the writing is not the most efficient so any help there would be great.
My current excel spreadsheet:
How it looks now
Sub Macro1()
'
' Macro1 Macro
'
Dim ticker As Range
Dim cell As Range
Dim start_row As Integer
Dim row As Integer
Dim top_investors As Integer
top_investors = 5
start_row = 2
Range("K2:U999999").ClearContents
Range("L" & start_row).Select
For Each ticker In Range("A2:A" & Cells(Rows.Count, 2).End(xlUp).row)
If Not IsEmpty(ticker) Then
ActiveCell.Formula = "=BDS(" & Chr(34) & ticker.Value & Chr(34) & ",""TOP_20_HOLDERS_PUBLIC_FILINGS"",""Endrow""," & Chr(34) & top_investors & Chr(34) & ",""Endcol"",""9"")"
For Each cell In Range("K" & start_row & ":" & "K" & start_row + top_investors)
row = start_row
Range("K" & row).Select
cell.Value = ticker.Value
row = row + 1
Next cell
start_row = start_row + top_investors
Range("L" & start_row).Select
End If
Next ticker
End Sub
Well, I guess you need to do something like:
Sub Macro1()
'
' Macro1 Macro
'
Dim ticker As Range
Dim cell As Range
Dim start_row As Integer
Dim row As Integer
Dim top_investors As Integer
Dim mySheet as Worksheet
top_investors = 5
start_row = 2
Sheets.Add.Name = "myNewSheet"
mySheet = ThisWorkbook.Sheets("myNewSheet")
Range("K2:U999999").ClearContents
Range("L" & start_row).Select
For Each ticker In Range("A2:A" & Cells(Rows.Count, 2).End(xlUp).row)
If Not IsEmpty(ticker) Then
mySheet.Range("define your Range").Formula = "=BDS(" & Chr(34) & ticker.Value & Chr(34) & ",""TOP_20_HOLDERS_PUBLIC_FILINGS"",""Endrow""," & Chr(34) & top_investors & Chr(34) & ",""Endcol"",""9"")"
For Each cell In (mySheet?.)Range("K" & start_row & ":" & "K" & start_row + top_investors)
row = start_row
mySheet.Range("K" & row).Select
cell.Value = ticker.Value
row = row + 1
Next cell
start_row = start_row + top_investors
Range("L" & start_row).Select
End If
Next ticker
End Sub
That won't work yet, but I guess you got the idea of working with "mySheet" and know better than me were to add it in your code. Maybe you need to google a little bit about the correct syntax.
If you have a recent Excel version (that has the LET spreadsheet function) then VBA is not strictly necessary for what you want to achieve.
For example, if you tickers are in the range A4:A7 on 'Sheet 1', you can collect all the data in 'Sheet 2':
The formula in Sheet2!A4: =Sheet1!A4
The formula in Sheet2!B4: =LET(data,BDS(A4,$B$2,"Array=TRUE"),s,SEQUENCE(1,$B$1),INDEX(data,s,1))
Then fill the formulae down as needed. The dynamic number of investors is in cell Sheet2!B1, but this can be hard-coded.
The main 'trick' is to use the "Array=TRUE" option in the BDS() call. This returns the data in a dynamic array, which can be indexed into.
I have have the following problem with vba and would like to ask you for help.
I hope I haven't overseen a similar question in the froum
I have several sheets in an excel workbook. On each sheet I would like to run the same formulas. The formula gets its data from the cell C3 on the same sheet and should run until the end of the data in column C xxx . The length of the data is different on each sheet. Each sheet has its own data set.
The code I have written works fine in the sense that it works itself through through the sheets starting from sheet 2 until the end of the sheets.
The code gets executed via an icon in the toolbar.
On each sheet I have values what the formulas should use. The values in column C are different long. Some have for example just 15 some have over 300000.
For example, if I press the icon when I'm on sheet 1 with no data in column C the macro takes the first 15 values/range of the column for the formulas in all sheets. Which means I miss all values from for example at sheet 3 with 300000 values. If I am on sheet 3 and press the icon there I takes the 300000 values/range and uses the range of the 300000 values in all the other sheets.
If I run the code without the loop on each sheet it works fine. It selects the right range with values of the column.
There are no empty cells in the column.
Has anyone an idea what is wrong in the code that it does not select the real amount of values in column C for the different sheets?
I work on a mac with excel 14.
The following code is what I have so far:
Sub Start()
Dim i As Long
lastrow = Cells(Rows.Count, 3).End(xlUp).Row
For i = 2 To Worksheets.Count
With Sheets(i)
.Range("K11").Formula = "=COUNT(C3:C" & lastrow & ")"
.Range("K12").Formula = "=MEDIAN(C3:C" & lastrow & ")"
.Range("K13").Formula = "=AVERAGE(C3:C" & lastrow & ")"
.Range("K14").Formula = "=MIN(C3:C" & lastrow & ")"
.Range("K15").Formula = "=MAX(C3:C" & lastrow & ")"
.Range("K16").Formula = "=STDEVP(C3:C" & lastrow & ")"
End With
Next i
End Sub
You have to use .Cells to make it refer to the object in the With statement, otherwise it refers to the current sheet:
Sub Start()
Dim i As Long
For i = 2 To Worksheets.Count
With Sheets(i)
lastrow = .Cells(Rows.Count, 3).End(xlUp).Row
Debug.Print (i)
Debug.Print (lastrow)
.Range("K11").Formula = "=COUNT(C3:C" & lastrow & ")"
.Range("K12").Formula = "=MEDIAN(C3:C" & lastrow & ")"
.Range("K13").Formula = "=AVERAGE(C3:C" & lastrow & ")"
.Range("K14").Formula = "=MIN(C3:C" & lastrow & ")"
.Range("K15").Formula = "=MAX(C3:C" & lastrow & ")"
.Range("K16").Formula = "=STDEVP(C3:C" & lastrow & ")"
End With
Next i
End Sub
I am trying to delete rows till it meets my last row OR fill down rows to align with last row.
Sometimes my sheet will be like below where I need to delete rows to align with my last row number.:
However sometimes my sheet will be like below, where I need to fill down other columns:
Is there a function that can do this? I am finding it hard to determine when to fill up or fill down.
Thanks
keeping in mind the well known caveats of the use of UsedRange, you could give it a try
Dim lastRow As Long
With ActiveSheet ' <- change it to your actual sheet reference
With .UsedRange
lastRow = .Rows(.Rows.Count)
End With
End With
Please test the next code. It assumes that the reference column will be the seventh one and the one to check the 0 formulas value to be the sixth one. Your picture does not contain the columns header...
Sub DeleteRowsOrFillDownDiscontinuous()
Dim sh As Worksheet, lastR As Long, lastR1 As Long, lastCol As Long
Set sh = ActiveSheet
lastR = sh.Range("F" & rows.count).End(xlUp).row
lastR1 = Range("E" & rows.count).End(xlUp).row
lastCol = sh.cells(lastR1, Columns.count).End(xlToLeft).Column
If lastR < lastR1 Then
sh.rows(lastR + 1 & ":" & lastR1).EntireRow.Delete xlUp
ElseIf lastR > lastR1 Then
sh.Range("A" & lastR1, "E" & lastR1).AutoFill _
Destination:=sh.Range("A" & lastR1, sh.Range("E" & lastR))
sh.Range("G" & lastR1, "AG" & lastR1).AutoFill _
Destination:=sh.Range("G" & lastR1, "AG" & lastR)
sh.Range("AI" & lastR1, sh.cells(lastR1, lastCol)).AutoFill _
Destination:=sh.Range("AI" & lastR1, sh.cells(lastR, lastCol))
Else
MsgBox "Nothing te be processed. Everything aligned..."
End If
End Sub
Edited:
Adapted the code for F:F column as reference, AH:AH not changeable, too and existing columns to be processed after AH Column.
Please test it and send some feedback.
I wanted to convert below formula to VBA code.
=C1&"`"&K1&"`"&L1&"`"&J1
=VLOOKUP(M1,Data!$A:$J,9,)
=SUMPRODUCT(SUMIF(B1:B,B1,G1:G))
Currently i have enter this formula in 1st row and than copying this formula till the last row used which is taking lot time to apply formula because it has more than million row.
LR1 = Sheets("CRIMS").UsedRange.Rows.Count
Sheets("CRIMS").Range("M1:P1").AutoFill Destination:=Sheets("CRIMS").Range("M1:P" & LR1)
is there any way to convert this formula into VBA code?
For first formula the easiest way would be:
Range("M" & i).FormulaR1C1 = "=RC[-10]&""`""&K&""`""&L&""`""&J"
But for vlookup I prefer dictionaries/collections! It is much much faster.
If You have source data in Data sheet and You want to put that to CRIMS sheet to column M:
Sub vlookup()
Dim names As Range, values As Range
Dim lookupNames As Range, lookupValues As Range
Dim vlookupCol As Object
Dim lastRow As Long
Dim lastRow2 As Long
Dim objekt as Object
With Sheets("Data")
lastRow = Sheets("Data").Cells(Rows.Count, 1).End(xlUp).row
Set names = Sheets("Data").Range("A1:A" & lastRow)
Set values = Sheets("Data").Range("I1:A" & lastRow)
End With
Set objekt = BuildLookupCollection(names, values)
With Sheets("CRIMS")
lastRow2 = 1000000
Set lookupNames = .Range("M1:M" & lastRow)
Set lookupValues = .Range("N1:N" & lastRow)
End With
VLookupValues lookupNames, lookupValues, objekt
Set objekt = Nothing
End Sub
Function BuildLookupCollection(categories As Range, values As Range)
Dim vlookupCol As Object, i As Long
Set vlookupCol = CreateObject("Scripting.Dictionary")
On Error Resume Next
For i = 1 To categories.Rows.Count
Call vlookupCol.Add(CStr(categories(i)), values(i))
Next i
On Error GoTo 0
Set BuildLookupCollection = vlookupCol
End Function
Sub VLookupValues(lookupCategory As Range, lookupValues As Range, vlookupCol As Object)
Dim i As Long, resArr() As Variant
ReDim resArr(lookupCategory.Rows.Count, 1)
For i = 1 To lookupCategory.Rows.Count
resArr(i - 1, 0) = vlookupCol.Item(CStr(lookupCategory(i)))
Next i
lookupValues = resArr
End Sub
Quotation Marks need to be doubled in VBA
Try this:
For i = 1 To LR1
Range("M" & i).Formula = "=C" & i & "&""`""&K" & i & "&""`""&L" & i & "&""`""&J" & i
Range("N" & i).Formula = "=VLOOKUP(M" & i & ",Data!$A:$J,9,)"
Next i
(replace column letters with actual target column)
As mentioned in the comments Looping in this case is highly inefficient.
Use this Code to insert the formulas all at once. It still takes some time for 1 Milion rows though.
Range("M1:M" & LR1).Formula = "=C:C & ""`"" & K:K & ""`"" & L:L & ""`"" & J:J"
Range("N1:N" & LR1).Formula = "=VLOOKUP(M:M,Data!$A:$J,9,)"
In my excel sheet I have the following code:
=IF(ISERROR(MATCH(D2,'Sheet 2'!A:A,0)),"",NOW())
This basically checks to see if the value in D2 matches any values in column A:A in sheet 2, and then populates the cell with a date and time with NOW().
My problem is the date and time is counting up because I am using the NOW() function whereas what I need is the date to, in a way, take a snapshot of the date or freeze the date. This table I am creating is acting like a log so I need the date to stay as it is when it is put into the cell.
Any help with this is much appreciated.
You could have this automatically run, if you paste it in the code behind your sheet (Where the range theCells is the column where the timestamps are going):
Private Sub Worksheet_Change(ByVal Target As Range)
Dim KeyCells As Range
' The variable KeyCells contains the cells that will
' cause an alert when they are changed.
Set KeyCells = Range("theCells")
If Not Application.Intersect(KeyCells, Range(Target.Address)) _
Is Nothing Then
If Range(Target.Address).Value <> "" Then
Range(Target.Address).Copy
Range(Target.Address).PasteSpecial xlPasteVaues
End If
End Sub
Ok so I solved it, In my VBA I have the following code which pretty much creates a log file when my button is clicked, it takes various information in different cells and populates it in the next defined available row:
Sub copylog()
Dim LastRow As Long, ws As Worksheet
Dim wt As Worksheet
Set ws = Sheets("Create Log")
Set wt = Sheets("PDF Creation")
LastRow = ws.Range("A" & Rows.Count).End(xlUp).Row + 1
ws.Range("A" & LastRow).Value = wt.Range("N11").Value
ws.Range("B" & LastRow).Value = wt.Range("N12").Value
ws.Range("C" & LastRow).Value = wt.Range("N13").Value
ws.Range("D" & LastRow).Value = wt.Range("N14").Value
ws.Range("E" & LastRow).Value = wt.Range("N15").Value
ws.Range("F" & LastRow).Value = wt.Range("N16").Value
ws.Range("G" & LastRow).Value = wt.Range("AT19").Value
ws.Range("H" & LastRow).Value = wt.Range("AT21").Value
ws.Range("I" & LastRow).Value = wt.Range("AT23").Value
ws.Range("J" & LastRow).Value = wt.Range("AT25").Value
ws.Range("K" & LastRow).Value = wt.Range("AT27").Value
ws.Range("L" & LastRow).Value = wt.Range("A2").Value
ws.Range("M" & LastRow).Value = Environ("Username")
End Sub
The code above will populate a table in the next available row, for example, the first line:
ws.Range("A" & LastRow).Value = wt.Range("N11").Value
This will take the value that populates N11 in the PDF create sheet and populate the next available row in column A in the create log sheet (using copy and paste).
The line that has fixed my time problem is the line:
ws.Range("L" & LastRow).Value = wt.Range("A2").Value
In cell A2, I have the NOW() function and the button copies and pastes it into the next available space in column L (copies and pastes as TEXT).