Excel VBA renames the wrong sheet - vba

I have an excel macro-enabled workbook that has 5 sheets. One of these sheets is named "NC" and one is named "SC". I have part of the code which adds dates to these sheets' names.
Sheets("NC").Name = "NC" & Replace(Date, "/", "-")
Sheets("SC").Name = "SC" & Replace(Date, "/", "-")
Then later on if the reset button is clicked, I made a code to switch them back to previous "NC" and "SC" names but this is where I get the problem.
Sheets(2).Name = "NC"
Sheets(3).Name = "SC"
Sheets(2).Name = "NC" works fine
Sheets(3).Name = "SC" however, renames Sheet(4) instead
I thought these sheet codes or sheet numbers don't change no matter how you rearrange or reorder your sheet tabs. I don't understand why it accurately renamed Sheets(2) but not Sheets(3). Look at my project explorer below, it renames Sheets(4) instead from "NCToday" to "SC". Sheets(3) is showing "SC" in the picture but because this was manually reset but you can see the arrangement, the code Sheets(3).Name = "SC" SHOULD NOT have renamed Sheets(4) from "NCToday" to "SC".

Sheet(3) does not necessarily mean sheet3
Example:
If I type into the immediate window, ?worksheets(1).name, I get this result:
Sheet2
note that the system looks at the sheet order on the excel spreadsheet (Sheet2,Sheet1, Sheet3), not the order in the VBA Project (Sheet1,Sheet2,Sheet3)
To rename the sheets back, you may want to reverse the method you used to rename them initially:
Sheets("SC" & Replace(Date, "/", "-")).Name = "SC"

There are many ways to refer to a worksheet.
Using
Sheets(number).Name
'this will print all the names in the Sheets(i) order
for i = 1 to Sheets.count
debug.pring sheets(i).name & " at index " & i
next i
renames the sheet at index number in the workbook from left to right.
Using
Sheet2.name = "NC"
will rename the VBA object Sheet2 shown in the explorer.
I suspect you want to do:
Sheet2.Name = "NC"
Sheet3.Name = "SC"

You could potentially use the Like option to compare the sheet names before renaming ?
Dim s as Worksheet
For each s in Worksheets
if s.Name like "NC*" and not s.Name = "NCToday" then
s.Name = "NC"
end if
next
That could solve your page-shuffle without having to resort to "Do Not Re-Shuffle comments" ?
Comments like that are prone to misinterpretation and will likely have your code run into troubles and errors at some stage.
Better to try and mae it foolproof !
Goodluck !
Cheers !

Related

Copying Worksheets with Powerquery using VBA - breaks Query

I have a Worksheet called "TEMPLATE" with a PowerQuery "TEMPLATE_Query" in it which works. The Powerquery requests a CSV-file from a website.
Now, using VBA in a loop, I make N copies of this sheet, resulting in worksheets named "Template (X)" and Powerquerys named "TEMPLATE_Query (X)". X=1..N. In my VBA code, I modify the Powerquery Formulas to request a different CSV file. Until here, it works alright. The Powerquerys run and receive different CSV files in all those Worksheets.
Here's the problem:
When I change the name of the Worksheet using VBA during my loop where I create the copies, the Powerquerys fail afterwards. Saying like "Download failed, connection only". So apparently the Powerquery doesn't have a reference to the correct sheetname anymore. The same happens when I rename the Powerquery and leave the Worksheet Name the same.
My goal is, to rename the Worksheet AND the Powerquery both in my VBA loop.
But why does this break the Queries?
I had the same problem a little while ago. If I remember correctly, it breaks because the query still wants to access something with a different name. I don't know why Excel does not change the reference when you rename a query. It does not even automatically changes it if you rename it manually with a right click. If you look at the query, right click it and then switch over to properties or what ever the middle tab is called, there you can see some details.
Long story short, this is how I fixed mine:
Sub Create_new_connection()
'On Error Resume Next
'Count the current amount of queries and save that number to refer to it later
QueryCount = ThisWorkbook.Queries.Count
'Copy the template and rename it
ThisWorkbook.Sheets("Template").Copy after:=ThisWorkbook.Sheets("Template")
ThisWorkbook.Sheets(3).Name = "Put a name here"
'Change the name of the query
ThisWorkbook.Queries.Item(QueryCount + 1).Name = "New Query Name"
'Change the names of the new table
ThisWorkbook.Sheets(3).ListObjects(1).Name = "I had a table I wanted to rename"
'Change the formula of the new connection
NewFormula = Replace(ThisWorkbook.Queries.Item(1).Formula, ThisWorkbook.Sheets("Create New List").ListObjects("Template").DataBodyRange(1, 1), ThisWorkbook.Sheets("Create New List").ListObjects("FAUF").DataBodyRange(1, 1))
ThisWorkbook.Queries.Item(QueryCount + 1).Formula = NewFormula
'Connect the new table to the new connection and
ThisWorkbook.Sheets(3).ListObjects(1).QueryTable.WorkbookConnection = "Abfrage - " & ThisWorkbook.Queries.Item(QueryCount + 1).Name
ThisWorkbook.Sheets(3).ListObjects(1).QueryTable.Connection = "OLEDB;Provider=Microsoft.Mashup.OleDb.1;Data Source=$Workbook$;Location=" & """" & ThisWorkbook.Queries.Item(QueryCount + 1).Name & """" & ";Extended Properties=" & """" & """"
ThisWorkbook.Sheets(3).ListObjects(1).QueryTable.CommandText = "SELECT * FROM [" & ThisWorkbook.Queries.Item(QueryCount + 1).Name & "]"
'Refresh the new connection
ThisWorkbook.Sheets(3).ListObjects(1).QueryTable.Refresh BackgroundQuery:=False
End Sub
The second to last bunch, the 3 modifying the connection are the important ones. This is on a German Excel tho, so you may need to change the "Abfrage - " bit to fit your language. It's just important that you correctly change the WorkbookConnection, Connection and CommantText correctly.

Copying all sheets from one workbook to another

I have an XLTM Template and an xlsx workbook.
The XLSX workbook has around 300-400 sheets.
I am looking to copy sheets from XLSX to XLSM Template.
What is the fastest way to do it?
I would like to have the same sheet name and formats along with the values.
Here is a copy of the code that I am using,
For k = 1 To xlWkb.Worksheets.Count
xlWkb.Activate
xlWkb.Sheets(k).Select
xlWkb.Sheets(k).Cells.Copy
xlWkb2.Activate
xlWkb2.Sheets("Sheet" & k).Select
xlWkb2.Sheets("Sheet" & k).Range("A1").Select
xlWkb2.ActiveSheet.Paste ' changes the column width and all, I want those formats
xlWkb2.Sheets("Sheet" & k).Name = xlWkb.Sheets(k).Name
Next
First of all, remove the lines that have Activate and Select on them and restructure it more like this:
For k = 1 To xlWkb.Worksheets.Count
xlWkb.WorkSheets(k).Cells.Copy
xlWkb2.WorkSheets("Sheet" & k).Range("A1").Paste
xlWkb2.WorkSheets("Sheet" & k).Name = xlWkb.WorkSheets(k).Name
Next
Please, find next API
Sheets("SheetName").Copy Before:=Workbooks("WorkbookName").Sheets(1)
Workbooks("WorkbookName").Sheets(1).Name = Sheets("SheetName").Name
This method Copy entire Worksheet with formatting, range names, values, formulas.. etc.

Multi language Excel VBA Application

I basically created an Excel VBA application that manipulate Excel worksheets, so in the code, I use the string "Sheet1" to refer to the first sheet of a workbook, but when I try to use this application with the same code with a french version of Excel, it doesn't work until I translate "Sheet1" to "Feuil1". So my question is, is there a way to automatically adapt the code to any version of Excel ?
You can use the following ways to get a sheet from code:
(1) using by Sheets(sheet_index)
This way cannot be adapt because it take the sheet by sheet index (sheet index are start from 1). When sheet are change place, it cannot access the right sheet.So, it should not use.
For example: Set Feuil1Sheet = Sheets(1)
(2) using by (Name) of VBA editor
I think this way should not use never, because it takes the sheet by code name which can only visible by VBA editor(it shows as (Name) field in sheet properties). I think you are using this way for getting the first sheet. So, you not get the right sheet. One thing you need to know is that code name of every first sheet may not be Sheet1 always. It can be Sheet2 or Sheet4, etc.
For example: Set Feuil1Sheet = Sheet1
(3) using Worksheets("sheet-name") or Sheets("sheet-name")
This last way is a very compatible way and can be adapt in anywhere Excel because it take the sheet by its name. So, If names are equal, you will get the right sheet. So, use this for getting the sheet.
For example: Set Feuil1Sheet = Worksheets("Feuil1") or Set Feuil1Sheet = Sheets("Feuil1")
The only possible way I can think of to always reference "sheet1" in the local language is the following code.
Option Explicit
Public Sub GetLocalNameForNewSheets()
Dim strSheetName As String
Dim i As Long
i = ActiveWorkbook.Sheets.Count
ActiveWorkbook.Sheets.Add After:=Worksheets(i)
strSheetName = ActiveWorkbook.Worksheets(i + 1).Name
Application.DisplayAlerts = False
ActiveWorkbook.Worksheets(i + 1).Delete
Application.DisplayAlerts = True
Debug.Print strSheetName
For i = 1 To Len(strSheetName)
While IsNumeric(Mid(strSheetName, i, 1))
strSheetName = Replace(strSheetName, Mid(strSheetName, i, 1), "")
Wend
Next i
Debug.Print strSheetName
Debug.Print strSheetName & "1"
End Sub
Basically, I am asking Excel to create a new sheet and name it for me. Then, I am getting the new name which is "sheet" in the local language and remove from the string the number part. At the end, you can add the number "1" to reference the first sheet.

Calling an existing worksheet with vba by using its code name in excel

I am trying to set the formula of a cell to an if formula that uses data from an already existing sheet within the workbook. However whenever trying to reference the sheet i get a file dialog box that opens looking for the path for the sheet. Below you will find my code which loops through all existing sheets in the workbook and compares it to a sheet name when it finds a match it stores the sheet code name for the current and previous weeks. Once it has these I have an if statement that tries to access these sheets and compare values. It is at this point that I get the file dialog box. Any thoughts or suggestions would be greatly appreciated. Thank you. Sorry for formatting issues I will correct as soon as possible.
sheetName = CStr(Year(Now)) & " eDR FW" & CStr(Format(Date, "ww")) & "_2"
lastWeekName = CStr(Year(Now)) & " eDR FW" & CStr(Format(Date, "ww") - 1) & "_2"
For Each ws In ActiveWorkbook.Worksheets
If ws.Name = sheetName Then
sheetName = ws.CodeName
ElseIf ws.Name = lastWeekName Then
lastWeekName = ws.CodeName
End If
Next
rowRange = colLetter & "2:" & colLetter & CStr(sheetRowCount)
lineofBalance = "=IFERROR(IF(INDEX('" & lastWeekName & "'!$A$2:$W$10000,MATCH(A2,'" & sheetName & "'!$A$2:$A$10000,0),6)=F2,F2,CONCATENATE(""Updated: ""&F2)),CONCATENATE(""New: ""&F2))"
All you need to do to make this work is change both ws.Codename to ws.Name.
The .Codename property only contains the first name of the sheet when it was originally created (which is most likely something like "Sheet32") and not the current name of the worksheet. It CAN be changed but most likely will remain the same unless you REALLY intend to change it. The formula with the erroneous worksheet name then opens the dialog box to try to find a reference for that particular worksheet.
Excel's formulas are designed to work with the current worksheet name and not it's codename. The only useful way I can see of using the .Codename, is if you wanna make sure to always use a particular worksheet (within VBA) even if the name of the worksheet was changed at some point (by yourself or a user).

Gathering data with VBA from yet to be created worksheets

I have been asked to create summary worksheets for excel files that I don't populate. These are 'monthly' excel files with the worksheets 'usually' named as to the week commencing date. I say 'usually' as a spelling mistake might creep in or such that wont allow the sheet names to be predicted in advance of their creation. The worksheet wont be created until the week in question has begun.
What I am trying to do, though struggling with, is create some VBA code to copy a number of cells and ranges from each worksheet to a summary worksheet which will be hidden. The worksheets all follow the same formatting, the main info being: A1 as the weekstart date, O4 to R4 as 4 summary column headers and N5 to N30 as username info. O5 to R30 then has counts in them depending on the data within the worksheet.
I want to create some code that copies the weekstart date (A1) alongside each username that is not blank (N5:N30) and the values after in the corresponding row. As the column headers in O4 to R4 dont change these can stay static on the summary sheet.
Afraid I dont know too much about vba. I guess I would use Worksheets.Count to find the number of worksheets? Was going to modify the code on here but I dont know how to ensure each row of data goes on a new line in the summary worksheet?
use the ozgrid example but make this alteration:
.Range("A1").
to
.Range("A" & l).
then amend your original post with further questions + the actual code you are using.
I have amended ozgrid code with the following which may be more or less relevant to your query. If you can rephrase your query into a more task1, task2 way, it will then be easy to change the below script into something you want.
The below script just work as a module instead of a worksheet event which is easier to control, just create a sub module and copy paste it there then run it or you can also create a button on the worksheet to run, using developper tab and choose form or activex button linked to the macro SplitWs.
Sub SplitWs()
Dim wSheet As Worksheet, ws As Worksheet
Dim i As Long
Set wSheet = ThisWorkbook.Worksheets(1)
i = 1
With wSheet
.Columns(1).ClearContents
.Cells(1, 1) = "INDEX"
.Cells(1, 1).Name = "Index"
End With
For Each ws In Worksheets
If ws.Name <> wSheet.Name Then
i = i + 1
With wSheet
.Range("A1").Name = "Start_" & wSheet.Index
.Hyperlinks.Add Anchor:=.Range("A1"), Address:="", _
SubAddress:="Index", TextToDisplay:="Back to Index"
End With
wSheet.Hyperlinks.Add Anchor:=wSheet.Cells(i, 1), Address:="", _
SubAddress:="Start_" & wSheet.Index, TextToDisplay:=wSheet.Name
End If
Next ws
End Sub
I also change the 'l' variable into 'i' which is easier to read.
Hope it will be of help, else comment with the things to amend.
Pascal
http://multiskillz.tekcities.com