Move entire row when sorting column (Google Apps Script) - sorting

I have a list of names in Column B, and a bunch of data (ID number, bank account details, etc.) in columns C:AK that corresponds/belongs to the name in column B.
I want to sort column B alphabetically, but the entire rows data must move with the name when sorted.
E.g. Lets say Ted is in B2 and Amy is in B3. When I do myrange.sort(2), Ted will now move to B3, but C2:AK2 must also now become C3:AK3. Otherwise Amy's personal details will now show up in the same row as Ted.
Does that make sense?
Example code:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Summary');
var curRange = sheet.getRange("B2:B6");
curRange.sort(2);

Your range only contains a single column so naturally, calling the 'sort()' method ignores all other columns in the sheet. You should select the entire data range and then sort by the selected column
var sortRange = sheet.getRange("B2:AK");
sortRange.sort({column:2, ascending: true});

Related

Copy Data from one cell and insert them to another cell under a unique word or sentence

You will find two columns in the below link. Columns A and B. I want to insert the data in Columns A2 to Cell B2 under this line 'Critical Dates Meeting Comments:'
Dates
function myFunction() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet102");
var targetSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet102");
sheet.getRange("A2:A164").moveTo(targetSheet.getRange("B2:B164"));
}
I used the code but it only transfer the data from A to replace B.
Is there a way to alter this code or maybe use another one to insert data instead of replacing it?

Google Apps Script: Activate and sort rows when cells in given column are not blank

I'm extremely new to Apps Script and trying to make my first thing. It's a shopping list.
I want to create a function that will activate and then sort (by Column 1, 'Aisle #') all rows where there are values in a given other column (Column 3, 'Qty'). The idea is to sort the items on the list for that week (i.e., with a value filled in for Qty) by aisle to give me the order I should be looking for things. I do not want to sort items which are in the spreadsheet but without
a value for Qty.
Here is what I've got so far:
var sheet = ss.getActiveSheet()
var range = sheet.getDataRange();
var rangeVals = range.getValues()
function orderList2(){
if(rangeVals[3] != ""){
sheet.activate().sort(1, ascending=true);
};
};
I'm trying to use "if" to define which rows to activate before doing the sort (as I don't want to sort the entire sheet—I only want to sort the items I will be buying that week, i.e., the items with a value in Column 3). The script runs but ends up sorting the entire sheet.
The closest thing I could find was an iteration, but when I did it, it ended up only activating the top-left cell.
Any help you can provide would be greatly appreciated!
Cheers,
Nick
Answer:
Use Range.sort() instead of Sheet.sort() if you don't want to sort the entire sheet.
Explanation:
You want to sort the data according to the value in column A (Aisle #), if the corresponding value in C (Qty) is not empty.
If my assumption is correct, the rows where Qty is empty should go below the rest of data, and they should not be sorted according to their Aisle #.
In this case, I'd suggest the following:
Sort the full range of data (headers excluded) according to Qty, so that the rows without a Qty are placed at the bottom, using Range.sort() (if you don't need to exclude the headers, you can use Sheet.sort() instead).
Use SpreadsheetApp.flush() to apply the sort to the spreadsheet.
Use getValues(), filter() and length to know how many rows in the initial range have their column C populated (variable QtyElements in the sample below).
Using QtyElements, retrieve the range of rows with a non-empty column C, and sort it according to column 1, using Range.sort().
Code sample:
function orderList2() {
var sheet = SpreadsheetApp.getActiveSheet();
var firstRow = 2; // Range starts at row 2, header row excluded
var fullRange = sheet.getRange(firstRow, 1, sheet.getLastRow() - firstRow + 1, sheet.getLastColumn());
fullRange.sort(3); // Sort full range according to Qty
SpreadsheetApp.flush(); // Refresh spreadsheet
var QtyElements = fullRange.getValues().filter(row => row[2] !== "").length;
sheet.getRange(firstRow, 1, QtyElements, sheet.getLastColumn())
.sort(1); // If not specified, default ascending: true
//.sort({column: 1, ascending: false}); // Uncomment if you want descending sort
}
Reference:
Range.sort(sortSpecObj)

Remove all columns to the right of a specific column

I have an Excel template file with a dynamic number of columns that represent work week dates. Some users have decided to add their own subtotal columns to the right of those columns. I need a way to identify the first blank column, and then truncate that column and all columns following it.
I had previously been using the following script to remove all columns that begin with the word "Column":
// Create a list of columns that start with "Column" and remove them.
Removed_ColumnNum_Columns = Table.RemoveColumns(PreviousStepName, List.Select(Table.ColumnNames(PreviousStepName), each Text.StartsWith(_, "Column") )),
Based on being able to find the first ColumnXX column, I want to remove it and all columns after it
You can use List.PositionOf to get your ColumnIndex instead of parsing text.
I'd put it together like this:
// [...]
ColumnList = Table.ColumnNames(#"Promoted Headers"),
ColumnXX = List.Select(ColumnList, each Text.StartsWith(_, "Column")){0},
ColumnIndex = List.PositionOf(ColumnList, ColumnXX),
ColumnsToKeep = List.FirstN(ColumnList, ColumnIndex),
FinalTable = Table.SelectColumns(#"Promoted Headers", ColumnsToKeep)
Remove Columns after ColumnXX
Find the first column that begins with the name "Column" and delete that column and all columns following it. This parses the XX as the column index so you need to make sure you haven't deleted columns prior to this step. i.e. "Column35" needs to be the 35th column at this step in the code.
// Find the first ColumnXX column and remove it and all columns to the right.
ColumnXX = List.Select(Table.ColumnNames(#"Promoted Headers"), each Text.StartsWith(_, "Column")){0},
ColumnIndex = Number.FromText(Text.Middle(ColumnXX, 6,4)),
ColumnListToRemove = List.Range(Table.ColumnNames(#"Promoted Headers"),ColumnIndex-1),
RemovedTrailingColumns = Table.RemoveColumns(#"Promoted Headers", ColumnListToRemove),
To make this more robust I would prefer to have a way to identify the column index of columnXX without parsing the digits from it.

Finding a specific text in a cell then deleting its row

Okay, so I have a name list where I write names in. Those names go in alphabetical order in another list where I give the names numbers. But whenever I add or remove names, cell shift places but the numbers remain the same, so if Adam had 1 1 1 1 and Bobby 2 2 2 2, by adding Ben he will take Bobby's place (because of the alphabetical order) and have 2 2 2 2 while Bobby will have 0 0 0 0. How do I make the numbers go after the name?
Photos with the examples (watch where appleboy comes in):
The sheet: https://docs.google.com/spreadsheets/d/1rH-4wzAzgOZ31jfH8MPkFnLCLzET3tfiGQrxaUpIg6Y/edit#gid=2041472100
you don't have a lot of options...
you can either have your names in order as you add them, then assign numbers to them (both actions on the same sheet) and then use simple SORT formula in sheet2 to get alphabetically sorted those names.
=SORT(sheet1!A2:F)
the 2nd option is to set up a lookup table on some helper sheet3 and then use ArrayFormula with VLOOKUP to match the ID (unique names). and then in B2:
=ARRAYFORMULA(IFERROR(VLOOKUP(A2:A, sheet3!A:F, {2,3,4,5,6}, 0)))
the 3rd option would be to use a sorting script for a specified range
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("ChangeSheetNameHere");
var range = sheet.getRange("A2:Z");
function onEdit(e) {
range.sort([{column: 1, ascending: true}]);
}

Tables got over-written

I want to loop thru a dbf and create word table for each record meeting the condition, and I got a one-page report with only the last rec in a single table. Look like all records are written to the same table. I tried to use n = n + 1 to place the variable as an element to the table
oTable = oDoc.tables[n]
But seems it only support numerical rather than variable ?
You have to add each table as you go, making sure to leave space in between them (because Word likes to combine tables).
You'll need something like this inside your loop:
* Assumes you start with oDoc pointing to the document,
* oRange set to an empty range at the beginning of the area where you want to add the tables,
* and that nRows and nCols give you the size of the table.
oTable = oDoc.Tables.Add(m.oRange, m.nRows, m.nCols)
oRange = oTable.Range()
oRange.Collapse(0)
oRange.InsertParagraphAfter()
oRange.Collapse(0)
After this code, you can use oTable to add the data you want to add. Then, on the next time through the loop, you're ready to add another table below the one you just filled.

Resources