The job process is like below:
Use column A as a condition to query the spreadsheet DATA, and return the column * of the spreadsheet DATA.
But now my spreadsheet is facing the delay issue and lag problem ,
i have confuse how to settle it.
if is any wrong please forgive me
please check out the example sheets any suggestion is welcome,
and thanks at all
I believe your goal is as follows.
You want to reduce the process cost for retrieving your goal.
In your situation, how about using Google Apps Script as a direction? I thought that when Google Apps Script is used, the process cost might be able to be reduced. When Google Apps Script is used for your situation, it becomes as follows.
Sample script:
Please copy and paste the following script to the script editor of Google Spreadsheet and save the script. And, when you use this script using your provided Spreadsheet, please put a custom function of =SAMPLE('INPUT COL B'!B2:B,'DATA'!W2:AF) to a cell. By this, the result is returned.
function SAMPLE(srcValues, dataValues) {
const obj = dataValues.reduce((o, [w, ...v]) => {
const last = v.pop();
if (v.join("") != "") {
v.forEach(c => {
if (!o[c]) o[c] = [w, last];
});
}
return o;
}, {});
return srcValues.map(([b]) => obj[b] || [null, null]);
}
Testing:
When this script is for your provided Spreadsheet, the following result is obtained.
Note:
When the data becomes larger, the custom function might not be able to be used. At that time, please run the script by the script editor, custom menu, a button on Spreadsheet, and so on. The script is as follows. In this case, please copy and paste the following script to the script editor of Spreadsheet and save the script. And please run the function with the script editor. By this, in this script, the result value is put to the column "E" of "INPUT COL B" sheet.
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const [srcSheet, dataSheet] = ["INPUT COL B", "DATA"].map(s => ss.getSheetByName(s));
const srcValues = srcSheet.getRange("B2:B" + srcSheet.getLastRow()).getValues();
const dataValues = dataSheet.getRange("W2:AF" + dataSheet.getLastRow()).getValues();
const obj = dataValues.reduce((o, [w, ...v]) => {
const last = v.pop();
if (v.join("") != "") {
v.forEach(c => {
if (!o[c]) o[c] = [w, last];
});
}
return o;
}, {});
const res = srcValues.map(([b]) => obj[b] || [null, null]);
srcSheet.getRange(2, 5, res.length, res[0].length).setValues(res);
}
Reference:
Custom Functions in Google Sheets
Related
I am trying to copy conditional formatting from a GS range to another range and nothing is copied (no error). This is the snippet:
spreadsheet.getSheetByName('sheet_source').getRange(14,7,200,19).copyTo(spreadsheet.getSheetByName('sheet_target').getRange(14,7,200,19), SpreadsheetApp.CopyPasteType.PASTE_CONDITIONAL_FORMATTING, false);
If I use the same code but change the CopyPasteType to a different option, it works (see example below). The problem is that I only want conditional formatting copied so I need the PASTE_CONDITIONAL_FORMATTING to work. Please let me know if you have any suggestions.
spreadsheet.getSheetByName('sheet_source').getRange(14,7,200,19).copyTo(spreadsheet.getSheetByName('sheet_target').getRange(14,7,200,19), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
Per doubleunary's suggestion, I reformatted the script as follows, and it works:
function CndFmtFromTmplt_PasteCndFmt() {
//get spreadsheet
const spreadsheet = SpreadsheetApp.getActive();
//get sheets
const sheetSource = spreadsheet.getSheetByName("Template");
const sheetTarget = spreadsheet.getSheetByName("Test Sheet");
//clear rules
sheetTarget.clearConditionalFormatRules();
//get copy ranges
//const rangeSource = sheetSource.getRange(1, 1, sheetSource.getMaxRows(), sheetSource.getMaxColumns());
const rangeSource = sheetSource.getRange('A1:AF200');
const rangeTarget = sheetTarget.getRange('A1:AF200');
// copy values to destination range
rangeSource.copyTo(rangeTarget, SpreadsheetApp.CopyPasteType.PASTE_CONDITIONAL_FORMATTING,false);
};
The code you show looks fine, so it is unclear where the problem is. To make debugging easier, try structuring your code a bit, like this:
function test() {
const ss = SpreadsheetApp.getActive();
const sourceRange = ss.getRange('sheet_source!N7:S200');
const targetRange = ss.getRange('sheet_target!N7');
sourceRange.copyTo(targetRange, SpreadsheetApp.CopyPasteType.PASTE_CONDITIONAL_FORMATTING, false);
}
Check My Executions for failed executions, and view those logs to learn more about why the function fails. You can run the test() function in the script editor when testing.
I want to be able to pick say C3 from a list of Google spreadsheets in a folder.
I have a bunch of structurally identical sheets, but I'd like to be able to provide a sum of the values in C3 across say a hundred sheets in a directory.
Ultimately, would be great to highlight the largest or smallest value of C3 in a directory.
This could be useful in many places where you want to be able to aggregate, aggregate data.
SUGGESTION
If you have hundreds of Google spreadsheet files in a Google Drive folder, I agree with #player0 that it is best to use a script. With the Apps Script, you can:
Automate the process in iterating through Spreadsheet files in your Drive folder.
Filter only the Google Spreadsheet type (e.g you have a bunch of
different file types inside).
Get the range data & process them the way you want.
See this sample below that was derived from existing resources:
Script:
function readSheetsInAFolder() {
//FOLDER_ID is your drive folder ID
var query = '"FOLDER_ID" in parents and trashed = false and ' +
'mimeType = "application/vnd.google-apps.spreadsheet"';
var range = "C3"; //The range to look for on every Spreadsheet files in the Drive folder
var files, pageToken;
var finalRes = [];
do {
files = Drive.Files.list({
q: query,
maxResults: 100,
pageToken: pageToken
});
files.items.forEach(sheet => {
finalRes.push(viewRangeValue(range, sheet.id));
})
pageToken = files.nextPageToken;
} while (pageToken);
const arrSum = array =>
array.reduce(
(sum, num) => sum + (Array.isArray(num) ? arrSum(num) : num * 1),
0
);
var max = Math.max.apply(null, finalRes.map(function(row){ return Math.max.apply(Math, row) })); //Gets the largest number
var min = Math.min.apply(null, finalRes.map(function(row){ return Math.min.apply(Math, row); })); //Gets the smallest number
var sum = arrSum(finalRes) // Gets the sum
console.log('RANGE VALUES: %s \nRANGE: %s \nTOTAL SHEET(s) FOUND: %s \n________________\nSUM OF VALUES: %s \nLargest Value: %s \nSmallest Value: %s',finalRes,range, files.items.length,sum,max,min)
}
function viewRangeValue(range, sheetID) {
var sid = sheetID;
var rn = range;
var parms = { valueRenderOption: 'UNFORMATTED_VALUE', dateTimeRenderOption: 'SERIAL_NUMBER' };
var res = Sheets.Spreadsheets.Values.get(sid, rn, parms);
return res.values.map(num => {return parseInt(num)});
}
Demonstration:
Sample Test Drive Folder (w/ 3 test Spreadsheet files):
Every C3 cell on each of these 3 files contain either 0,10 or 6 value.
On the Apps Script Editor, I've added the Drive & Sheets API on the services:
Result
After running the script:
Resources:
Advanced Drive Service
Drive API Files: list
Sheets API spreadsheets.values.get
Max Value of an array
I am running the following script as its own .gs file
/**
* TITLE:
* Hide a row if a value is inputted.
*/
//**GLOBALS**
// Sheet the data is on.
var SHEET = "Norm Adam";
// The value that will cause the row to hide.
var VALUE = "Yes";
// The column we will be using
var COLUMN_NUMBER = 11
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
//Ensure on correct sheet.
if(SHEET == activeSheet.getName()){
var cell = ss.getActiveCell()
var cellValue = cell.getValue();
//Ensure we are looking at the correct column.
if(cell.getColumn() == COLUMN_NUMBER){
//If the cell matched the value we require,hide the row.
if(cellValue == VALUE){
activeSheet.hideRow(cell);
};
};
};
}
It works fine on a computer browser but on iOS device it doesn't work through the google sheets app and I actually can't even get the editable through safari. I read that only the onEdit function will work on a mobile device so I figured this should work. Is there another piece to this puzzle?
Thanks
Mike
(credit for script creation goes to: https://yagisanatode.com/2018/05/26/how-to-hide-a-row-based-on-a-cell-value-in-google-sheets-with-filter-or-google-apps-script/ )
Script V2:
I commented below on this still not working in iOS. I figured the simpler it was the more likely to work?
function onEdit(e) {
if (e.range.getColumn() == 11 && e.value == 'Yes') {
e.range.getSheet().hideRows(e.range.getRow());
}
}
getActive calls, especially ss.getActiveCell() should be avoided on mobile apps. Consider alternatives like e.range to get the edited range from event objects.
I am trying to create a script in Google Sheets that select a range and print it. I am trying to print some information based on some parameters. I have the following script that sets the desired range, but I do not see a way to print it using script.
function printInvoice() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange("A1:H46");
range.activate();
}
Any suggestions? Thanks!
You can use the following script:
var PRINT_OPTIONS = {
'size': 7, // paper size. 0=letter, 1=tabloid, 2=Legal, 3=statement, 4=executive, 5=folio, 6=A3, 7=A4, 8=A5, 9=B4, 10=B
'fzr': false, // repeat row headers
'portrait': true, // false=landscape
'fitw': true, // fit window or actual size
'gridlines': false, // show gridlines
'printtitle': false,
'sheetnames': false,
'pagenum': 'UNDEFINED', // CENTER = show page numbers / UNDEFINED = do not show
'attachment': false
}
var PDF_OPTS = objectToQueryString(PRINT_OPTIONS);
function onOpen(e) {
SpreadsheetApp.getUi().createMenu('Print...').addItem('Print selected range', 'printSelectedRange').addToUi();
}
function printSelectedRange() {
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getActiveRange();
var gid = sheet.getSheetId();
var printRange = objectToQueryString({
'c1': range.getColumn() - 1,
'r1': range.getRow() - 1,
'c2': range.getColumn() + range.getWidth() - 1,
'r2': range.getRow() + range.getHeight() - 1
});
var url = ss.getUrl().replace(/edit$/, '') + 'export?format=pdf' + PDF_OPTS + printRange + "&gid=" + gid;
var htmlTemplate = HtmlService.createTemplateFromFile('js');
htmlTemplate.url = url;
SpreadsheetApp.getUi().showModalDialog(htmlTemplate.evaluate().setHeight(10).setWidth(100), 'Print range');
}
function objectToQueryString(obj) {
return Object.keys(obj).map(function(key) {
return Utilities.formatString('&%s=%s', key, obj[key]);
}).join('');
}
You will also need to create an html file in your project (File>New>HTML File) with the name js, and paste in the following code:
<script>
window.open('<?=url?>', '_blank', 'width=800, height=600');
google.script.host.close();
</script>
This will create a button in your Sheets menu that will open a PDF with the selected range. You can modify some settings such as the print orientation, its size, or whether to show the gridlines or not on top of the script. If you still want to automatically print the ranges without having to manually go through the print dialog, you can either:
Send the document to your printer using GmailApp API class, if your printer supports such functionality.
Use Google Cloud Print. The following blog post may help you with that: https://ctrlq.org/code/20061-google-cloud-print-with-apps-script
I stumbled on your code quite by chance from an "unallowed question to stack overflow which actually seems to be exactly what I want - could not get any detail on how to print from App Script for sheets.
I have been trying it out but it falls over at the line in your sample
"var htmlTemplate = HtmlService.createTemplateFromFile('js');"
where the service cannot find 'js'. Afraid I do not understand what an html template is anyway - are you able to explain?
I have a set of data. What i am looking forwards is to add 2 blank rows after each set of 3 values like this
Hope to get help in getting this solved.
you can find the sample google sheet here : https://docs.google.com/spreadsheets/d/11nMvUWn3xcTfxlk4v30KruPr03HSheMk1jrxZPpJ_p4/edit?usp=sharing
Thanks
Shijilal
Solution:
IF it's the third row, Add 3 bunnies separated by a space, else keep the values as it is
JOIN them all and SPLIT by a bunny and TRANSPOSE
Sample:
=ARRAYFORMULA(TRANSPOSE(SPLIT(TEXTJOIN("🐇",1,IF(MOD(ROW(A2:A16),3)=1,A2:A16&REPT("🐇 ",3),A2:A16)),"🐇")))
Some time ago, I created this custom function that may help you. I changed it slightly to meet your requirement and added it to the script editor.
function rowsBetween(range, s, rowsWithData, text) {
var n = [],
a = [],
i = 0;
while (i < s) {
a.push(text
)
i++;
}
range.forEach(function(r, i) {
n.push(r);
if((i + 2) % rowsWithData == 1) {
a.forEach(function(x) {
n.push(x);
});
}
});
return n;
}
This script will allow you to enter in the spreadsheet this (custom) formula (see also cell E2)
=rowsBetween(A2:A16, 2, 12,)
See if that works for you?