Creating and sorting a dynamic table - excel

I have a sub where i want to create a table so that i can sort it afterwards (one of the columns must be in descending order).
The sub works when i have the workbook open and on the correct worksheet.
When i try to run the code without having to look at the worksheet at the same time, the following problem pops up:
"Method 'Range' of object_global' failed"
"Can't execute code in break mode"
This is what my sub looks like. The row is static but the column length changes from time to time.
Sub create_the_table_investeringsforeninger()
' Best used when row length is static
Dim sht As Worksheet
Dim LastRow As Long
Dim Lrow As Long
Set sht = ThisWorkbook.Worksheets(2)
'Refresh UsedRange
ThisWorkbook.Worksheets(2).UsedRange
Lrow = Range("D" & Rows.Count).End(xlUp).Row
sht.ListObjects.Add(SourceType:=xlSrcRange, Source:=sht.Range("A2:F2" & Lrow)).Name = "Investeringsforeninger"
'Sort Range "Investeringsforeninger"
Range("investeringsforeninger").Sort Key1:=Range("F2"), order1:=xlDescending, Header:=xlYes
End Sub
The whole of my code is supposed to run without me having to open the document first (for this i am using a vbs document).

You are missing references to your Worksheet, therefore it only works when it is the active sheet. I deleted your UsedRange line as it does nothing.
Sub create_the_table_investeringsforeninger()
' Best used when row length is static
Dim sht As Worksheet
Dim LastRow As Long
Dim Lrow As Long
Set sht = ThisWorkbook.Worksheets(2)
Lrow = sht.Range("D" & Rows.Count).End(xlUp).Row
sht.ListObjects.Add(SourceType:=xlSrcRange, Source:=sht.Range("A2:F2" & Lrow)).Name = "Investeringsforeninger"
'Sort Range "Investeringsforeninger"
sht.Range("investeringsforeninger").Sort Key1:=sht.Range("F2"), order1:=xlDescending, Header:=xlYes
End Sub

Related

Write a dynamic sum formula vba that takes range from another sheet

screenshot of code
I am trying to calculate sum in cell "I13" of sheet2 with inputs based on the dynamic range.
Formula
range("I13").formula= "=sum('sheet1'!A1:A3)"
works but the range can be dynamic. For this I have used lr to identify the last row in the range
lr=cells(rows.count,1).end(xlup).row
Now, I want to modify the above formula such that in place of A3, it takes last cell. i.e. A&lr
Have tried using range("I13").formula= "=sum('sheet1'!A1:A"&lr)", but it results in error
Sub MMM()
Windows("Template.xlsx").activate
sheets("sheet1").select
range("a1").select
lr=cells(rows.count,1).end(xlup).row
sheets("sheet2").select
'this code works. But want dynamic range
'range("I13").formula = "= SUM('sheet1'!A1:A3)"
range("I13").formula = "= sum('sheet1'!A1:A&lr)"
End Sub
you can try to define the variable:
Option Explicit ' It should be used when you define variable
Sub MMM()
Dim lr as Range ' Define variable
Windows("Template.xlsx").activate
sheets("sheet1").select
range("a1").select
lr=cells(rows.count,1).end(xlup).row
sheets("sheet2").select
range("I13").formula = "= sum('sheet1'!A1:A&lr)"
End Sub
You have to join the string for the formula like this:
"=SUM('Sheet1'!A1:A" & lastRow & ")"
Alternatively:
If you set the whole range to be summed then you can use the Address of this range. The External-parameter returns the sheet name as well.
Sub MMM()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim wsSource As Worksheet: Set wsSource = wb.Worksheets("Sheet1")
Dim wsTarget As Worksheet: Set wsTarget = wb.Worksheets("Sheet2")
Dim rgDataToSum As Range
With wsSource
Set rgDataToSum = .Range("A1", .Cells(.Rows.Count, 1).End(xlUp))
End With
wsTarget.Range("I13").Formula = "=SUM(" & rgDataToSum.Address(True, True, External:=True) & ")"
End Sub

Not Incrementing Rows

I have a Macro that makes a header and I wanted to create a variant of it that allows me to append my array called headers() to the next empty row in a sheet. I've tried playing around with the macro even replacing the Range.insert with PasteSpecial however the results are the same: Whenever I run the Macro in the VBA Editor it appends rows like I want, however when I run it via a Command button as a part of another sub it just overwrites the same row (row 2) even if I fill in row 2 with something.
Sub MEData()
' Find Next Empty Row & Append ME Data
Dim headers() As Variant
Dim ws As Worksheet
Dim wb As Workbook
Dim lastRow As Long
Dim lr As Long
Set wb = ActiveWorkbook
Set ws = ThisWorkbook.Sheets("ME Data")
If DesignChangeECN = "" Then
DesignChangeECN = "Not Design Change"
End If
headers() = Array(VBA.Environ("UserName"), Now(), MPP_ECN,
MPP_ECN_Description, DesignChangeECN, Dept, ShortChangeDescription,
ChangeType, "Additional Notes", _
"Open", "Submitted")
lastRow = Cells(ws.Rows.Count, 2).End(xlUp).row
Rows(lastRow).PasteSpecial
With ws
For i = LBound(headers()) To UBound(headers())
.Cells(lastRow, 1 + i).Value = headers(i)
Next i
End With
End Sub
I'm not super proficient in VBA so I'm not sure if I'm misusing or utilizing something incorrectly or if there is something super simple that I'm missing.
I found the answer after quite a few hours of reading and research best methods of handling arrays and rows. I settled on using a range instead of insert as that would make more sense, especially when I figured out that I could have a range set to my array It became simpler.
I did still immediately suffer from not incrementing rows however I fix that by having using ws.Activate I figured out that since the sheet that ran the Macro via a command button was acting as the "Active Sheet" called .Activate fixed my issue.
Sub MEData()
' Find Next Empty Row & Append ME Data
Dim headers() As Variant
Dim ws As Worksheet
Dim wb As Workbook
Dim lastRow As Long
Set wb = ActiveWorkbook
Set ws = ThisWorkbook.Sheets("ME Data")
If DesignChangeECN = "" Then
DesignChangeECN = "Not Design Change"
End If
headers() = Array(VBA.Environ("UserName"), Now(), MPP_ECN, MPP_ECN_Description, _
DesignChangeECN, Dept, ShortChangeDescription, ChangeType, "Additional Notes", _
"Open", "Submitted")
ws.Activate
lastRow = Cells(ws.Rows.Count, 1).End(xlUp).row + 1
ws.Range("A" & lastRow & ":K" & lastRow) = headers()
End Sub

VBA - Get name of last added sheet

I am looking for a code to get the name of the last added sheet to Excel.
I have tried this...
Sub test()
Dim lastAddedSheet As Worksheet
Dim oneSheet As Worksheet
With ThisWorkbook
Set lastAddedSheet = .Sheets(1)
For Each oneSheet In .Sheets
If Val(Mid(oneSheet.CodeName, 6)) > Val(Mid(lastAddedSheet.CodeName, 6)) Then
Set lastAddedSheet = oneSheet
End If
Next oneSheet
End With
MsgBox lastAddedSheet.Name & " was last added."
End Sub
But it does not really work.
You can't reliably know what sheet was last added, because a sheet can be inserted before or after any existing sheet in a workbook, see Sheets.Add documentation.
Unless you're the one adding it. In which case, all you need to do is capture the Worksheet object returned by the Add method:
Dim newSheet As Worksheet
Set newSheet = wb.Worksheets.Add
Debug.Print newSheet.Name
Extracting the digits from the CodeName isn't going to be reliable either - especially if you assume that every sheet's code name begins with 5 letters. On a German machine, the CodeName of what we see as Sheet1 would be Tabelle1 - but then again the role of that digit is strictly to ensure uniqueness of the names of the VBComponent items in the VBA project, and none of it says it has anything to do with any sort of ordering.
As per #MathieuGuindon his answer, I can't think of any "simple" way to safely return the name of the latest added sheet. However if you willing to sacrifice some designated space in your project to store CodeNames you could try to utilize the Workbook_NewSheet event.
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Dim lr As Long
With Sheets("Blad1")
lr = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
.Cells(lr, 1) = ActiveSheet.CodeName
End With
End Sub
Obviously you need to optimize this to add names when adding sheets during runtime. In this simplified example I manually added the existing sheet "Blad1", and upon adding new sheets, the list grew.
When deleting you can utilize the SheetBeforeDelete event, like so:
Private Sub Workbook_SheetBeforeDelete(ByVal Sh As Object)
Dim ws As Object
Dim lr As Long, x As Long
Dim rng1 As Range, rng2 As Range, cl As Range
With Sheets("Blad1")
lr = .Cells(.Rows.Count, "A").End(xlUp).Row + 1
Set rng1 = .Range("A2:A" & lr)
For Each ws In ActiveWindow.SelectedSheets
For Each cl In rng1
If cl = ws.CodeName Then
If Not rng2 Is Nothing Then
Set rng2 = Union(rng2, cl)
Else
Set rng2 = cl
End If
End If
Next cl
Next ws
End With
If Not rng2 Is Nothing Then
rng2.Delete
End If
End Sub
Now to get the latest added sheet we can refer to the last cell in our designated range:
Sub LastAdded()
Dim lr As Long
With ThisWorkbook.Sheets("Blad1")
lr = .Cells(.Rows.Count, "A").End(xlUp).Row
Debug.Print "Last added sheet is codenamed: " & .Cells(lr, 1)
End With
End Sub
My take on it is that it would be safest to use the CodeName since they are least likely to get changed and are unique. We can also safely keep using our rng variable since there will always be at least one worksheet in your project (and that might just be the designated one if you protect it). Working in this project will now keep track of latest added worksheet.
Sheets could be a Chart or a Worksheet.
You could try use Worksheets instead of Sheets in your code.
sub test()
Dim lastAddedSheet As Worksheet
Dim oneSheet As Worksheet
With ThisWorkbook
Set lastAddedSheet = .WorkSheets(1)
For Each oneSheet In .WorkSheets
If Val(Mid(oneSheet.CodeName, 6)) > Val(Mid(lastAddedSheet.CodeName, 6)) Then
Set lastAddedSheet = oneSheet
End If
Next oneSheet
End With
MsgBox lastAddedSheet.Name & " was last added."
End Sub

Print name of the sheet along with copied cell

I have this code where it loops through all the sheets in the workbook and copies the value in F9 of each sheet and pastes it in "Summary" sheet column A. How can I also print the sheet name in column B? So the value is next to the sheet name in the "Summary" sheet.
code:
Sub loopsheet()
Dim wks As Worksheet
For Each wks In ThisWorkbook.Worksheets
If Not wks.Name = "Summary" Then
wks.Range("F9:F" & wks.Cells(Rows.Count, "F").End(xlUp).Row).Copy _
Destination:=Worksheets("Summary").Cells(Rows.Count, "A").End(xlUp).Offset(1)
End If
Next
End Sub
Thank you
Create two variables to track the last rows of your sheets as you loop. This will help with readability in your code. The combination of these two variables can also help you deduce the size of the range where you need to drop your sheet name.
I believe cLR + pLR - 11 is the size of range. The offset is due to headers, LR offset, and the fact that you are starting your copy from the 9th row. After you run this, you may need to tweak it up or down one if i'm wrong.
Option Explicit
Sub LoopSheet()
Dim ws As Worksheet
Dim Summary As Worksheet: Set Summary = ThisWorkbook.Sheets("Summary")
Dim cLR As Long, pLR As Long
For Each ws In ThisWorkbook.Worksheets
If ws.Name <> Summary.Name Then
cLR = ws.Range("F" & ws.Rows.Count).End(xlUp).Row
pLR = Summary.Range("A" & Summary.Rows.Count).End(xlUp).Offset(1).Row
ws.Range("F9:F" & cLR).Copy Summary.Range("A" & pLR)
Summary.Range(Summary.Cells(pLR, 2), Summary.Cells(cLR + pLR - 11, 2)).Value = ws.Name
End If
Next ws
End Sub

excel vba: Range gives Argument Not Optional error message

In excel vba I'm tryin to select a range of values starting in Cell"O2", (O from Oyster) down to the end of the sheet,
I'm trying:
Range("O2", Range.End(xlDown))
But that fails with Argument Not Optional. What am i doing wrong?
I'm using Excel 2010.
Don't use xlDown Declare your Objects and then work with it.
Use this
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim LRow As Long
Dim rng As Range
'~~> Change this to the relevant sheet name
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
'~~> Find last row in Col O which has data
LRow = .Range("O" & .Rows.Count).End(xlUp).Row
'~~> This is your range
Set rng = .Range("O2:O" & LRow)
With rng
'~~> Whatever you want to do
End With
End With
End Sub
To select the range from O2 to the last filled cell in that column, you could use:
Range("O2", Range("O2").End(xlDown)).Select
But that has a few problems, including the fact that it will "stop" at any blanks, and that you should avoid using Select unless absolutely necessary. Also, you should get in the habit of qualifying your ranges, e.g., specifying which worksheet they're in. Given all that, I propose something like this, assuming you wanted to turn the cells in the range red:
Sub test()
Dim LastRow As Long
Dim ws As Excel.Worksheet
Set ws = ActiveSheet
With ws
LastRow = .Range("O" & .Rows.Count).End(xlUp).Row
.Range("O2:O" & LastRow).Interior.Color = vbRed
End With
End Sub
Maybe you need
Range("O2", Range("O2").End(xlDown)).Select
?

Resources