I am attempting to write a script in Google Sheets that will read column D and if the cell contains, amongst others, the word "Apple" then it will copy the information from the same row in column B to a different sheet in cell(s) C28:C29.
Any help on starting the script would be greatly appreciated. Thanks!
function myfunc101() {
const sss = SpreadsheetApp.getActive();
const ssh = sss.getSheetByName('Sheet1');
const ssr = 2;
const srg = ssh.getRange(ssr,1,ssh.getLastRow() - ssr +1,4);
const svs = srg.getValues();
const tss = SpreadsheetApp.openById('tssid');
const tsh = tss.getSheetByName('Sheet1');
let c28 = [];
let c29 = [];
//let d = 0;//add this to delete current row of ssh
svs.forEach((r,i)=>{
if(r[3].toString().includes('Apple')) {
c28.push(r[1]);
c29.push(r[3]);
//sh.deleteRow(i+ssr-d++);//add this to delete current row of ssh
}
});
tsh.getRange('C28').setValue(c28.join(', '));
tsh.getRange('C29').setValue(c29.join(', '));
}
if C28 and C29 are merged and you want all of the data in C28 then replace last two lines with: tsh.getRange('C28').setValue(tsh.getRange('C28').getDisplayValue() + c28.join(', ') + c29.join(', '));
Related
I'm in the process of creating a script that'll merge data from multiple Google sheets onto one.
As I'm new to this, I'm having trouble figuring out an error I keep getting.
It states 'Exception: Range not found' in line 26 of the script.
I'm assuming, maybe incorrectly that there's something wrong with the range I'm using in my variables as to which data to merge onto the main sheet. But changing that doesn't seem to help.
Any tips, advice, or things to try is greatly appreciated.
Here's a link to the sheets.
https://docs.google.com/spreadsheets/d/1hv9zANMWzDBpKDWQ3hbDjX4nezEtOoptFbY0PYn_c5Y/edit?usp=sharing
Here's the code for the script.
function
myFunction() {
//FILTER({'Workout1'}) !E15:AA26,"DATA TAB 1 - ROW "&ROW('Workout1'!E15:E26)},'Workout1'!E15:E26<>"");
//FILTER({'Workout2'}) !E15:AA26,"DATA TAB 2 - ROW "&ROW('Workout2'!E15:E26)},'Workout2'!E15:E26<>"");
//FILTER({'Workout3'}) !E15:AA26,"DATA TAB 3 - ROW "&ROW('Workout3'!E15:E26)},'Workout3'!E15:E26"");
//FILTER({'Workout1'}) !E15:AA26,"DATA TAB 1 - ROW "&ROW('Workout1'!E15:E26)},'Workout1'!E15:E26<>"");
//setvariables
const masterSheet = "Data";
const ignoreSheets = ["Dashboard"];
const dataRange = "E15:AA26";
const checkRange = "E15:E26";
//end set variables
const ss = SpreadsheetApp.getActiveSpreadsheet();
const allsheets = ss.getSheets();
const filteredlistofsheets = allsheets.filter(s => ignoreSheets.indexOf(s.getSheetName()) == -1);
let formulaArray = filteredlistofsheets.map(s => `FILTER({'${s.getSheetName()}'$!{datarange},"${s.getSheetName()} - ROW "&ROW('${s.getSheetName()}!${checkRange},ROW "&ROW('${s.getSheetName()}'!${checkRange}<>"")`);
let formulaText = "={" + formulaArray.join(";") + "}";
ss.getSheetByName(masterSheet).getRange("masterSheetFormulaCell").setformula(formulaText);
}
Thanks very much.
You can do this without scripts using REDUCE.
=QUERY(
REDUCE({0,0,0,0},
{"Workout1",
"Workout2",
"Workout3"},
LAMBDA(acc,cur,
{acc;
INDIRECT(cur&"!E15:E26"),
BYROW(INDIRECT(cur&"!K15:O26"),LAMBDA(row,IFERROR(AVERAGE(row)))),
BYROW(INDIRECT(cur&"!Q15:U26"),LAMBDA(row,IFERROR(AVERAGE(row)))),
BYROW(INDIRECT(cur&"!W15:AA26"),LAMBDA(row,IFERROR(AVERAGE(row))))})
),
"select Col1,
sum(Col2),
sum(Col3),
avg(Col4)
where Col1 is not null
group by Col1
label Col1 'Exercise',
sum(Col2) 'Reps For Each Set',
sum(Col3) 'Weight Per Set (lbs.)',
avg(Col4) 'Rest Between Sets (sec.)'",1)
function mergeAllToFirst() {
const ss = SpreadsheetApp.openById("Spreadsheet ID");
let sht;
ss.getSheets().forEach((sh, i) => {
if (i == 0) {
sh.clearContents()
sht = sh;
} else {
let vs = sh.getDataRange().getValues();
sht.getRange(sht.getLastRow() + 1, 1).setValue(sh.getName());
sht.getRange(sht.getLastRow() + 1,1,vs.length,vs[0].length).setValues(vs);
}
})
}
Just wanted to know if there was a method of updating a cell based on a date that was selected using the date criteria via data validation.
Ideally, it would be used to log comments inputted into a cell. The user, upon changing the date cell, would be able to see the comment made on that specific date.
I look forward to hearing any ideas.
Cheers
Checking Date Column to set status to weekold
function weekold() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet Name');
const [hA, ...vs] = sh.getDataRange().getValues();
let idx = {};
hA.forEach((h,i) => idx[h]=i);
const dt = new Date();
const dtv = new Date(dt.getFullYear(),dt.getMonth(),dt.getDate()-7).valueOf()
let vo = vs.map(r => {
if(new Date(r[idx['Date']]).valufOf() <= dtv ) {
r[idx['Status']] = "Week Old"
}
return [r[idx['Status']]];
});
sh.getRange(2,idx['Status']) + 1,vo.length,vo[0].length).setValues(vo);
}
Im currently trying to move in bulk all the rows from a sheet where the checkbox is selected, I was trying to use "newFilterCriteria" but the one I use (found online) check on specific words while I want to use checkboxes.
The code so far does:
Get the source page, declare the filter criteria
function create_filter(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Fridge"); // DECLARE THE SOURCE PAGE
var range = sheet1.getRange("A5:J"); // DECLARE THE RANGE TO BE FILTERED LATER
var filter = range.createFilter();
var Filter_Criteria1 = SpreadsheetApp.newFilterCriteria().withCriteria(true); // HERE IS THE PROBLEM, THE ORIGINAL CODE SAYS "newFilterCriteria().whenNumberGreaterThan(1000);" BUT INSTEAD OF A NUMBER, I NEED A FILTER BASED ON CHECKBOXES BEING EITHER TRUE OR FALSE
var add_filter1 = filter.setColumnFilterCriteria(1,Filter_Criteria1);
Logger.log("Filter has been added.");
var range = sheet1.getDataRange();
var new_sheet = ss.insertSheet(); // CREATE THE DESTINATION TAB
new_sheet.setName("TEST"); // NAME THE DESTINATION TAB AS "TEST"
range.copyTo(new_sheet.getRange(1,1));
filter.remove();
}
Any suggestions or help? Thank you! I tried looking around but havent get to find the right way to filter with the checkboxes.
Something else: Not sure if I can avoid an iteration since there are many rows to copy and it would be a slow process I think, is there a way to say something like a query such as "select all rows where column 1 is true"?
The image is just an example of the table.
Thanks!
Move Checked
function myfunk() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
const vs = sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).getValues();
let a = [];
let d = 0;
vs.forEach((r, i) => {
if (r[0] == true) {
a.push(r)
sh.deleteRow(i + 2 - d++);
}
});
if (a) {
ss.insertSheet('Test').getRange(1, 1, a.length, a[0].length).setValues(a);
}
}
Use whenTextEqualTo true, for filtering in checkboxes:
const Filter_Criteria1 = SpreadsheetApp.newFilterCriteria().whenTextEqualTo('TRUE').build()
I made a similar request a few days ago using the following link:
How to copy a specific row from one sheet to another (Google Apps Script)
Now I have new requirements for which I need your help:
the script should copy specific rows that have value "No" in column T from one sheet to another sheet. It is important that it copies the values and the formatting.
the complete row should be copied.
after successful copying, the row should be deleted in the sourcesheet.
Can you please help me? Thank you very much!
Below you can find #Marios solution so far. At this point again many thanks!
const ss = SpreadsheetApp.getActiveSpreadsheet();
const srcSheet = ss.getSheetByName("[Overview] All_Cases");
const tarSheet = ss.getSheetByName("OPS_FUNNEL");
const data = srcSheet.getDataRange().getValues().filter(r=>r[21]=='No').map(r => [r[0]]);
var tarlast = tarSheet.getRange("A:A").getValues().filter(String).length;
if (data.length>0){
tarSheet.getRange(tarlast+1,1,data.length,1).setValues(data);
}
Explanation:
You can store the deleted row indexes inside the filter function itself and then use the classical approach to delete rows backwards.
Solution:
Column T has an array index of 19, not 21. Be careful with this.
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const srcSheet = ss.getSheetByName("[Overview] All_Cases");
const tarSheet = ss.getSheetByName("OPS_FUNNEL");
const rowsD = [];
const data = srcSheet.getDataRange().getValues()
.filter((r,i)=>{
let val = r[19]=='No';
if(val){
rowsD.push(i+1);
return val;
}
});
if (data.length>0){
tarSheet.getRange(tarSheet.getLastRow()+1,1,data.length,data[0].length).setValues(data);
for (var i = rowsD.length - 1; i>=0; i--) {
srcSheet.deleteRow(rowsD[i]);
}
};
}
I am trying to compile data from one sheet containing order information to another sheets cell based on each customers name. I'd like to take the title of the column as well as the count for the item(s) they have ordered. I tried to brute force it with a formula in Google Sheets but the formula messes up and stops giving the correct information so I figured using a scripts function would be better for what I am trying to do. I made a new sheet to test a script on but have little experience and can't seem to make any progress.
I'd like to get the title(top row) of each column and the count of the item(s) into the order column on sheet2 base on the matching names on both sheets. If anyone could help or provide some insight it would be greatly appreciated.
Here is the code I came up with:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var orders = ss.getSheetByName("Sheet2");
var data = ss.getSheetByName("Sheet1");
var names = orders.getRange("Sheet2!A2:A5");
var name = names.getValues();
var startRow = 1
var endRow = ss.getLastRow()
var getRange = ss.getDataRange();
var getRow = getRange.getRow();
var title = data.getRange("Sheet1!B1:J1");
var item = title.getValues();
var itemCell = data.getRange("Sheet1!B2").getValue();
var orderCell = orders.getRange(2,2).getValue()
Logger.log(itemCell)
if(itemCell>=0){
orders.getRange(2,2).setValue("item1 x " +itemCell)
}
currently this only has the desired effect on one cell and does not complete the row and repeat on next column.
Here is how I adjusted the code to try and fit a larger data set:
function myFunction() {
const srcSheetName = "Test Data";
const dstSheetName = "Order Changes";
const ss = SpreadsheetApp.getActiveSpreadsheet();
// 1. Retrieve source values.
const srcSheet = ss.getSheetByName(srcSheetName);
//I changed values 1,1 to change the values that were retreived
const [[, ...header], ...srcValues] = srcSheet.getRange(1, 1,
srcSheet.getLastRow(), srcSheet.getLastColumn()).getValues();
// 2. Create an object using the source values.
const srcObj = srcValues.reduce((o, [a, ...v]) => {
const temp = v.reduce((s, r, i) => {
if (r.toString() != "") s += `${header[i]} ${r}`;
return s;
}, "");
return Object.assign(o, {[a]: temp || ""});
}, {});
// 3. Retrieve the header column of destination values.
const dstSheet = ss.getSheetByName(dstSheetName);
//I changed values 2 or 1 to adjust the destination of values
const dstRange = dstSheet.getRange(2, 1, dstSheet.getLastRow() - 1);
const dstValues = dstRange.getValues();
// 4. Create the output values using the header column and the object.
const putValues = dstValues.map(([a]) => [srcObj[a] || ""]);
// 5. Put the values.
dstRange.offset(0, 1).setValues(putValues);
}
after making the changes and running the code the values would either not appear or appear in the wrong column with incorrect data.
Goal of function Update:
Match names in Sheet2!A with names in Sheet1!F
If a match is found combine header and value of cells in Sheet1!N1:BQ.
This should be from the same row of the matched name in Sheet1!F (example:
John Smith lm14 1, lm25 2, lm36 1)
Place combined data into Sheet2!C
Repeat for every name in Sheet2!A
header and cell value should not be combined if value < 0
I hope this helps to clarify any misunderstanding.
Here is are better example images:
I believe your goal as follows.
In your goal, the upper image in your question is the output you expect, and the cells "B2" should be item1 1 item3 1 item6 2 item9 3 when the lower input situation is used.
You want to achieve this using Google Apps Script.
In order to achieve above, I would like to propose the following flow.
Retrieve source values.
Create an object using the source values.
Retrieve the header column of destination values.
Create the output values using the header column and the object.
Put the values.
Sample script:
Please copy and paste the following script to the script editor of the Spreadsheet and set the source sheet name and destination sheet name, and run myFunction.
function myFunction() {
const srcSheetName = "Sheet1";
const dstSheetName = "Sheet2";
const ss = SpreadsheetApp.getActiveSpreadsheet();
// 1. Retrieve source values.
const srcSheet = ss.getSheetByName(srcSheetName);
const [[, ...header], ...srcValues] = srcSheet.getRange(1, 1, srcSheet.getLastRow(), srcSheet.getLastColumn()).getValues();
// 2. Create an object using the source values.
const srcObj = srcValues.reduce((o, [a, ...v]) => {
const temp = v.reduce((s, r, i) => {
if (r.toString() != "") s += `${header[i]} ${r}`;
return s;
}, "");
return Object.assign(o, {[a]: temp || ""});
}, {});
// 3. Retrieve the header column of destination values.
const dstSheet = ss.getSheetByName(dstSheetName);
const dstRange = dstSheet.getRange(2, 1, dstSheet.getLastRow() - 1);
const dstValues = dstRange.getValues();
// 4. Create the output values using the header column and the object.
const putValues = dstValues.map(([a]) => [srcObj[a] || ""]);
// 5. Put the values.
dstRange.offset(0, 1).setValues(putValues);
}
References:
getValues()
setValues(values)
reduce()
map()
Added 1:
About your current issue, the reason of your issue is that the ranges of source and destination are the different from the sample image in your question. My suggested answer is for the sample images in your initial question. When you changed the structure of the Spreadsheet, it is required to modify my suggested script. But from I changed values 1,1 to change the values that were retrieved and I changed values 2 or 1 to adjust the destination of values, I couldn't understand about your modified script. So as the additional script, I would like to modify my suggested answer for your updated question.
From your updated question and replyings, I understood that the source range and destination range are "N1:BQ" and "A52:C79", respectively. From this, please modify above sample script as follows.
From:
const [[, ...header], ...srcValues] = srcSheet.getRange(1, 1, srcSheet.getLastRow(), srcSheet.getLastColumn()).getValues();
To:
const [[, ...header], ...srcValues] = srcSheet.getRange("N1:BQ" + srcSheet.getLastRow()).getValues();
and
From:
dstRange.offset(0, 1).setValues(putValues);
To:
dstRange.offset(0, 2).setValues(putValues);
Added 2:
About your current issue, the reason of your issue is that the ranges of source and destination are the different from your 1st updated question in your question. My suggested answer is for the sample images in your 1st updated question. When you changed the structure of the Spreadsheet, it is required to modify my suggested script.
From your 2nd updated question, I understood that the source range and destination range are "F1:BQ" (the column "F" is the title and the columns "N1:BQ" are the values.) and "A2:C", respectively. From this, please modify above sample script as follows.
function myFunction() {
const srcSheetName = "Sheet1";
const dstSheetName = "Sheet2";
const ss = SpreadsheetApp.getActiveSpreadsheet();
// 1. Retrieve source values.
const srcSheet = ss.getSheetByName(srcSheetName);
const [[,,,,,,,, ...header], ...srcValues] = srcSheet.getRange("F1:BQ" + srcSheet.getLastRow()).getValues();
// 2. Create an object using the source values.
const srcObj = srcValues.reduce((o, [a,,,,,,,, ...v]) => {
const temp = v.reduce((s, r, i) => {
if (r.toString() != "") s += `${header[i]} ${r}`;
return s;
}, "");
return Object.assign(o, {[a]: temp || ""});
}, {});
// 3. Retrieve the header column of destination values.
const dstSheet = ss.getSheetByName(dstSheetName);
const dstRange = dstSheet.getRange(2, 1, dstSheet.getLastRow() - 1);
const dstValues = dstRange.getValues();
// 4. Create the output values using the header column and the object.
const putValues = dstValues.map(([a]) => [srcObj[a] || ""]);
console.log(srcObj)
// 5. Put the values.
dstRange.offset(0, 2).setValues(putValues);
}