How to divide a google spreadsheet (with about 100 sheets) in two (or more) spreadsheets (of about 50 sheets each) in google-apps-script ?
Alas, due to a google bug (see https://productforums.google.com/d/topic/docs/H2ZakBguOgk/discussion), I can't copy the entire spreadsheet file and delete some sheets in each spreadsheets.
I can only copy sheets one by one on another spreadsheet, then delete the original sheet(s) if copy is a success.
Thanks in advance ;)
Here is a code snippet that should do what you want, I didn't test it so maybe you'll have to tweak some details but the general idea is there...
EDIT : I tested and made the corrections to make it work... sorry for the typos in first version
function splitSS() {
var oldFileID = 'original ss Id'
var newFile = DocsList.getFileById(oldFileID).makeCopy()
var newFileID = newFile.getId()
var ss = SpreadsheetApp.openById(newFileID);
Logger.log(ss.getNumSheets())
var todel = parseInt((ss.getNumSheets())/2);
Logger.log(todel)
var tokeep = ss.getNumSheets()-todel
Logger.log(tokeep)
for (pa=ss.getNumSheets()-1;pa>tokeep;--pa){
ss.setActiveSheet(ss.getSheets()[pa]);
var delsheet = ss.deleteActiveSheet(); // delete sheets begining with the last one
Utilities.sleep(400);
}
var ssold = SpreadsheetApp.openById(oldFileID);
for (pa=todel;pa>1;--pa){
ssold.setActiveSheet(ssold.getSheets()[pa]);
var delsheet = ssold.deleteActiveSheet(); // delete sheets begining with the last one
Utilities.sleep(400);
}
}
Related
So here is my problem, I have a script for copying a bunch of independent one sheet google spreadsheets into one master spreadsheet as tabs, but because I'm using "title contains" it creates sheets (tabs) for non existent spreadsheets (in the example below: it will make "ADC Lunch" even though that sheet doesn't exist). I have about 50 of these in a script, what is the best way to ensure that only the sheets that have actual spreadsheet files correspondent to their name exist in my master spreadsheet? I was thinking maybe a "if then" like IF(ID=true, sheet.copyTo(destination).setName("ADC Breakfast")) but I don't have much experience in api script yet so I don't know how to formulate it around this function. Any help would be appreciated, thank you.
Illustration:
"Spreadsheet 1"
"Spreadsheet 2" --> compiled --> Master Spreadsheet (with 3 sheets)
"Spreadsheet 3"
Problem:
Master Spreadsheet searches for Spreadsheet X by "title contains" search, if it doesn't find one of the spreadsheets with the specific requirements, it just copies another spreadsheet that is close enough into the master spreadsheet as Spreadsheet X. How can I make it so it will only copy a spreadsheet to the master spreadsheet (as a tab) if it actually exists and fulfills the "title contains" parameters? I hope this clarifies things, sorry for my poor description.
function ArrayBuilder() {
var filesource = DriveApp.searchFiles('title contains "ADC Breakfast" and parents in "File_ID"');
while(filesource.hasNext()){
var File = filesource.next();
var ID = File.getId();
}
var name = File.getName()
var source = SpreadsheetApp.openById(ID);
var sheet = source.getSheets()[0];
var destinationID = "File_ID";
var destination = SpreadsheetApp.openById(destinationID);
sheet.copyTo(destination).setName("ADC Breakfast");
Finding Spreadsheets that have only one sheet
I know this isn't the answer to your question but perhaps it will help you think about it another way. This function finds Spreadsheets that only have 1 sheet and it appends the file name, file id and sheet name to a spreadsheet. It also adds an extension to the file name like (n) where n is an integer indicating how many files have had that name. With the information in the spreadsheet you could probably figure out which ones you would like to copy into your master spreadsheet or if you wish assistance in modifying it please let me know.
function findSpreadsheetsWithOnlyOneSheet() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('File Data Sheet');
var nA=[];
var nObj={};
var files=DriveApp.getFolderById('Folder Id').getFilesByType(MimeType.GOOGLE_SHEETS);
while(files.hasNext()) {
var file=files.next();
var id=file.getId();
var name=file.getName();
if(Sheets.Spreadsheets.get(id).sheets.length==1) {
var sheetname=Sheets.Spreadsheets.get(file.getId()).sheets[0].properties.title;
if(nA) {
if(nA.indexOf(name)==-1) {
nA.push(name);
sh.appendRow([name,id,sheetname]);
}else{
if(nObj.hasOwnProperty(name)) {
nObj[name]+=1;
}else{
nObj[name]=1;
}
sh.appendRow([name + '(' + nObj[name] + ')',id,sheetname])
}
}else{
sh.appendRow([name,id,sheetname]);
}
}
}
}
This is what my spreadsheet looks like:
Sheets API version 4
DriveApp Class
I'm attempting to write a script to continuously update two spreadsheets so that the information put in one always goes into the other.
The full project is to create a master spreadsheet with 50 people on it and each one of them has their own sheet/page, however they aren't allowed to access this master sheet as they are not allowed to see the other peoples data. (I am currently unaware of any viewing permission commands but I'm pretty sure there aren't any).
So the solution that I have been considering is creating 50 other spreadsheets and each of them will have a single sheet with all of the same information as the master Spreadsheet and the name of the sheet will be the same as on the master page.
I found this code on another post that was for a similar problem
function onEdit(e) {
// Get the event object properties
var range = e.range;
var value = e.value;
//Get the cell position
var row = range.getRowIndex();
var column = range.getColumnIndex();
exportValue(row,column,value)
}
function exportValue(row,column,value) {
var ss = SpreadsheetApp.openById(targetID);
var s = ss.getSheetByName(targetSheetName);
var target = s.getRange(row, column);
target.setValue(value);
}
in this I understand what everything is doing except the ("var range = e.range; var value = e.value;") lines, is ths what im looking for or not, idk
Thanks in advance
:)
Does anyone know a script that would let me copy data from cells A3:E1000 on Sheet1 and paste it to Sheet2. After pasting I need it to delete the exact data that it copied from Sheet1 (Sheet2 will still have copied data) and I need it to do this everyday at 11:30pm. I need Sheet2 to be able to keep taking the data forever as a digital archive of the data that is being copied daily from Sheet1. I hope this makes sense. I can't figure it out. When I run this it works if I run dailyLog and then run clearRange separately. When I run autoArchive it deletes the data from Info sheet but doesn't paste it into the Archive sheet.
function autoArchive(){
dailyLog();
clearRange();
}
function dailyLog() {
var ss = SpreadsheetApp.openById("SheetID").getSheetByName("Info");
var sourceSheet = ss.getSheetByName('Info');
var logSheet = ss.getSheetByName('Archive');
var lastRow = logSheet.getLastRow();
var range = sourceSheet.getDataRange();
range.copyTo(logSheet.getRange(lastRow + 2, 1), {contentsOnly: false});
}
function clearRange() {
var sheetActive =
SpreadsheetApp.openById("SheetID").getSheetByName("Info");
var start, end;
start = 2;
end = sheetActive.getLastRow() - 1;
sheetActive.deleteRows(start, end);
}
have a look at the record macro function it will generate Google Apps Script for you. Just records the steps you take and give it a name so you only need to click the macro in the menu or use a shortcut.
#Cooper the current limit for a spreadsheet is 5.000.000 cells. Doesn't matter if it is in one sheet or all sheets together. However this might be increased in the nearby future.
Use SpreadsheetApp.flush(); to force Google Apps Script to apply the changes made so far.
Example:
function autoArchive(){
dailyLog();
SpreadsheetApp.flush();
clearRange();
}
I have a bunch of data I want to put in to multiple sheets, and to do it manually would take time and I would like to learn scripting too.
So say I have a sheet with the states in one column.
I would like to have a script make new sheets based off the values of that column, and make a hyperlink to those sheets, and sort the sheets alphabetically.
In each sheet, I need to have the A1 cell the same name as the sheet.
Here is an example of states
Any suggestions would be helpful
Edit:
This is code that can make sheets based on the values of the columns.
function makeTabs() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var last = sheet.getLastRow();//identifies the last active row on the sheet
//loop through the code until each row creates a tab.
for(var i=0; i<last; i++){
var tabName = sheet.getRange(i+2,1).getValue();//get the range in column A and get the value.
var create = ss.insertSheet(tabName);//create a new sheet with the value
}
}
(note the "sheet.getRange(i+2,1" assumes a header, so pulls from the first column, starting on the second row)
I still need to:
Add a hyper link in the index sheet to the State's sheet: example: A2 on the Index sheet
would be =HYPERLINK("#gid=738389498","Alabama")
Also I need the A1 cell of the State's page to have the same info as
the index. example: Alabama's A1 cell would be =Index!A2
You could take a look at this script:
function createSheets(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var indexSheet = ss.getSheetByName('Index');
var indexSheetRange = indexSheet.getDataRange();
var values = indexSheetRange.getValues();
var templateSheet = ss.getSheetByName('TEMPLATE_the_state');
templateSheet.activate();
var sheetIds = [],
state,
sheetId,
links = [];
for (var i = 1 ; i < values.length ; i++){
state = values[i][0];
sheetId = undefined;
try{
var sheet = ss.insertSheet(state, {template: templateSheet});
SpreadsheetApp.flush();
sheet.getRange("A1:B1").setValues([['=hyperlink("#gid=0&range=A' +(i+1)+'","go back to index")',state]]);
sheetId = sheet.getSheetId();
}
catch (e) { Logger.log('Sheet %s already exists ' , sheet)}
sheetIds.push([sheetId,state]);
}
sheetIds.forEach(function(x){
links.push(['=HYPERLINK("#gid='+x[0]+'&range=A1","'+x[1]+'")']);
});
indexSheet.getRange(2,1,links.length,links[0].length).setValues(links) // in this case it is clear to us from the outset that links[0].length is 1, so we could have written 1
}
Note that in my version, I created a template sheet from which to base all the state sheets from. This wasn't what you asked for, but I wanted to see what it would do.
The resulting sheet is here: https://docs.google.com/spreadsheets/d/1Rk00eXPzkfov5e3D3AKOVQA2UdvE5b8roG3-WeI4znE/edit?usp=sharing
Indeed, I was surprised at how long it took to create the full sheet with all the states - more than 250 secs. I looked at the execution log, which I have added to the sheet in its own tab. There it is plain to see that the code is quick, but sometimes (why only sometimes, I don't know) adding a new tab to the spreadsheet and/or flushing the formulas on the spreadsheet is very slow. I don't know how to speed it up. Any suggestions welcome. (I could try the Google Sheets API v4, probably would be much faster ... but that is much more work and tougher to do.)
Situation:
I have a spreadsheet with 20 sheet.
I have other script that copy sheets from other spreadsheet every days to this spreadsheet-
I need to delete every days some specific sheet from a particular spreadsheet.
Problem:
When the script ends to clear the sheets, the spreadsheet hangs and I have to exit and re-enter to the spreadsheet.
I'll appreciate if anyone can help to tunning this script to work without hangging the spreadsheet.
Script:
function shellDeleteSheets(){
var sheets = ['Sheet1','Sheet2','Sheet3','Sheet4','Sheet5'];
for (var s in sheets){
deleteSheetName(sheets[s]);
}
}
function deleteSheetName(stname) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName(stname);
if(!sh) {
return;
}
ss.setActiveSheet(sh);
ss.deleteActiveSheet();
Utilities.sleep(400);
SpreadsheetApp.flush();
}
Try this version I use without issue
function DeleteSheets(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ['sheet1','sheet2','sheet3'];
var numberOfSheets = ss.getSheets().length;
for(var s = numberOfSheets-1; s>0 ; s--){ // in my case I never delete the first sheet
SpreadsheetApp.setActiveSheet(ss.getSheets()[s]);
var shName = SpreadsheetApp.getActiveSheet().getName();
if(sheets.indexOf(shName)>-1){
var delSheet = ss.deleteActiveSheet();
Utilities.sleep(500);
}
}
SpreadsheetApp.setActiveSheet(ss.getSheets()[0]);// send me back to first sheet
}
You could of course use the array of names as an argument for the function or - that's what I do in some cases - give the names of the sheet I need to keep, in this case the if condition is just different .
the sleep can be 400 mS, not sure it makes any difference, I use 500 because at some time I found it more reliable... and I (try to) never change a working solution ;-)
EDIT following your comment :
to make active the sheet called 'Updated' just change the last line of the code like this :
SpreadsheetApp.setActiveSheet(ss.getSheetByName('Updated'));
please note also that I moved this line in the original code, outside of the loop, sorry for this small error ^^