First post here.
I've been tasked with snapshotting some data in an Excel file and storing it for use in a Power BI report. I'm relatively new to Officescript and the Power Platform, with some background in code. I was learning Officescript as I was making this, so I would expect there's a lot of optimization to do in my code.
I have to collect data on two levels: CAMs (employees) and Customers, then multiple counts for each. I do this by running a for loop for Customers nested in the CAM for loop. The script enters the current search into designated search boxes in helper ranges that calculate the necessary counts. The script then copies the helpers into a larger list, removes zero data rows, and then copies the lists to the historical data list.
To run the snapshot script automatically, I use a Power Automate flow to run a desktop flow that refreshes my data connections in the Excel file, then (back in the cloud flow) I run the Officescript. The problem is that the script keeps timing out. I've tried chunking out the code, but it still seems to be timing out.
Hoping someone can help me identify ways to make this run faster so it doesn't time out.
Code is here:
function main(workbook: ExcelScript.Workbook) {
// refresh workbook data
workbook.refreshAllDataConnections;
// set worksheet variable names
let data = workbook.getWorksheet("Detail"); // set Detail worksheet
let ss = workbook.getWorksheet("Status Snapshot"); // set Status Snapshot worksheet
let ssh = workbook.getWorksheet("Status Snapshot Helper"); // set Status Snapshot Helper worksheet
let vs = workbook.getWorksheet("Violation Snapshot");
let vsh = workbook.getWorksheet("Violation Snapshot Helper");
// Safeguard against duplicate data
// clear Status Snapshot
let todayDate = ssh.getRange("C1").getValue(); // get today's date
let ssRange = ss.getRange("A:A").getUsedRange().getRowCount(); // set used range in column A
for (let i = 1; i <= ssRange; i++) { // initiate for loop
if (ss.getRange("A" + i).getValue() === todayDate) { // check if date is today
ss.getRangeByIndexes(i - 1, 0, i - 1, 6).clear(ExcelScript.ClearApplyTo.contents); // clear row data
}
}
// clear Violation Snapshot
let vsRange = vs.getRange("A:A").getUsedRange().getRowCount(); // set used range in column A
for (let i = 1; i <= vsRange; i++) { // initiate for loop
if (vs.getRange("A" + i).getValue() === todayDate) { // check if date is today
vs.getRangeByIndexes(i - 1, 0, i - 1, 6).clear(ExcelScript.ClearApplyTo.contents); // clear row data
}
}
// Clear Snapshot Helper Data
// clear Status Snapshot Helper
ssh.getRange("C2:G2").getExtendedRange(ExcelScript.KeyboardDirection.down).clear(ExcelScript.ClearApplyTo.contents);
// clear Violation Snapshot Helper
vsh.getRange("C2:H2").getExtendedRange(ExcelScript.KeyboardDirection.down).clear(ExcelScript.ClearApplyTo.contents);
// Get last row of Unique CAM column
let rangeCAM = ssh.getRange("A:A").getUsedRange();
let uniqueCAMRows = rangeCAM.getRowCount();
// Get last row of Unique Customer column
let rangeCust = ssh.getRange("B:B").getUsedRange();
let uniqueCustRows = rangeCust.getRowCount();
// snapshot loop
// Status Snapshot loop
for (var i = 2; i <= uniqueCAMRows; i++) { // initiate for loop
let searchCAM = ssh.getRange("A" + i); // set the CAM to search for
let searchCAMdest = ssh.getRange("H2"); // set the CAM search destination
searchCAMdest.copyFrom(searchCAM, ExcelScript.RangeCopyType.values, false, false); // paste CAM into search destination
for (var j = 2; j <= uniqueCustRows; j++) {
let searchCust = ssh.getRange("B" + j);
let searchCustdest = ssh.getRange("I2");
searchCustdest.copyFrom(searchCust, ExcelScript.RangeCopyType.values, false, false);
let dataRange = ssh.getRange("H2:K4"); // set snapshot data range for current CAM
let sshRange = ssh.getRange("D:D").getUsedRange(); // get used range in snapshot data
let sshNextEmpty: number = sshRange.getRowCount() + 1; // get row count in snapshot data
let dataDest = ssh.getRange("D" + sshNextEmpty); // find data paste destination
dataDest.copyFrom(dataRange, ExcelScript.RangeCopyType.values, false, false); // paste snapshot data into destination
}
}
// Violation Snapshot loop
for (var i = 2; i <= uniqueCAMRows; i++) { // initiate for loop
let searchCAM = vsh.getRange("A" + i); // set the CAM to search for
let searchCAMdest = vsh.getRange("I2"); // set the CAM search destination
searchCAMdest.copyFrom(searchCAM, ExcelScript.RangeCopyType.values, false, false); // paste CAM into search destination
for (var j = 2; j <= uniqueCustRows; j++) {
let searchCust = vsh.getRange("B" + j);
let searchCustdest = vsh.getRange("J2");
searchCustdest.copyFrom(searchCust, ExcelScript.RangeCopyType.values, false, false);
let dataRange = vsh.getRange("I2:M5"); // set snapshot data range for current CAM
let vshRange = vsh.getRange("D:D").getUsedRange(); // get used range in snapshot data
let vshNextEmpty: number = vshRange.getRowCount() + 1; // get row count in snapshot data
let dataDest = vsh.getRange("D" + vshNextEmpty); // find data paste destination
dataDest.copyFrom(dataRange, ExcelScript.RangeCopyType.values, false, false); // paste snapshot data into destination
}
}
// Delete all 0 rows for Snapshot Helper data
// Status Snapshot
let sshRange: number = ssh.getRange("D:D").getUsedRange().getRowCount(); // set used range in column D
for (let i = 2; i <= sshRange; i++) { // initiate for loop
let g = ssh.getRange("G" + i).getValue(); // get column G number
if (g === 0) { // check if all 3 counts = 0
ssh.getRangeByIndexes(i - 1, 2, 1, 6).delete(ExcelScript.DeleteShiftDirection.up); // delete row if 0
i--; // subtract 1 from i to compensate for deleted
}
}
// Violation Snapshot
let vshRange: number = vsh.getRange("D:D").getUsedRange().getRowCount(); // set used range in column D
for (let i = 2; i <= vshRange; i++) { // initiate for loop
let g = vsh.getRange("G" + i).getValue(); // get column G number
let h = vsh.getRange("H" + i).getValue(); // get column H number
let sum: number = g + h;
if (sum === 0) { // check if sum counts = 0
vsh.getRangeByIndexes(i - 1, 2, 1, 6).delete(ExcelScript.DeleteShiftDirection.up); // delete row if 0
i--; // subtract 1 from i to compensate for deleted
}
}
// paste dates into the snapshot helper data
// Status Snapshot
let dateCells = ssh.getRange("C1"); // set date cell
let sshUsedRows: number = ssh.getRange("D:D").getUsedRange().getRowCount(); // get used rows number in Snapshot Helper data
let sshUsedRange = ssh.getRange("C2:C" + sshUsedRows); // set the range to fill dates
sshUsedRange.copyFrom(dateCells, ExcelScript.RangeCopyType.values, false, false); // copy date cell into range needing dates
// Violation Snapshot
let dateCellv = vsh.getRange("C1"); // set date cell
let vshUsedRows: number = vsh.getRange("D:D").getUsedRange().getRowCount(); // get used rows number in Snapshot Helper data
let vshUsedRange = vsh.getRange("C2:C" + vshUsedRows); // set the range to fill dates
vshUsedRange.copyFrom(dateCellv, ExcelScript.RangeCopyType.values, false, false); // copy date cell into range needing dates
// Copy and paste Snapshot Helper Data
// Status Snapshot
let sshDataRange = ssh.getRange("C2:G2").getExtendedRange(ExcelScript.KeyboardDirection.down); // get Snapshot Helper data range
let ssNextRow: number = ss.getRange("A:A").getUsedRange().getRowCount() + 1; // get Snapshot used range
let ssDataDest = ss.getRange("A" + ssNextRow); // set data paste destination
ssDataDest.copyFrom(sshDataRange, ExcelScript.RangeCopyType.all, false, false); // copy and paste data into Snapshot
// Violation Snapshot
let vshDataRange = vsh.getRange("C2:H2").getExtendedRange(ExcelScript.KeyboardDirection.down); // get Snapshot Helper data range
let vsNextRow: number = vs.getRange("A:A").getUsedRange().getRowCount() + 1; // get Snapshot used range
let vsDataDest = vs.getRange("A" + vsNextRow); // set data paste destination
vsDataDest.copyFrom(vshDataRange, ExcelScript.RangeCopyType.all, false, false); // copy and paste data into Snapshot
}
getRange
,CopyFrom
CopyFrom
, consider usingsetValue
.For example:
for
loop is not related to eitheri
(outer loop variable) or Col A, but it has been executed multiple times. (from i=2 touniqueCAMRows
)