質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

Q&A

解決済

1回答

1212閲覧

Google Apps Script 串刺し演算 シート範囲指定 実行時間を短縮したい

hiroshiorz

総合スコア15

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

Google

Googleは、アメリカ合衆国に位置する、インターネット関連のサービスや製品を提供している企業です。検索エンジンからアプリケーションの提供まで、多岐にわたるサービスを提供しています。

0グッド

0クリップ

投稿2018/07/30 08:22

編集2018/08/01 02:39

前提・実現したいこと

スプレッドシート初心者でスクリプトを書くのも初めてですのでわかりにくい所あるかもしれませんがよろしくお願いします。

指定シートの指定範囲内の串刺し演算を行いたいです。
作ったソースコードでは時間内に処理ができずもっと簡潔にする必要があるのですが、その方法がわかりませんので、ご教授いただきたく思い投稿させていただきました。

シートが「集計」「マスタ」「テンプレ」「2018.7.29」「2018.7.28」・・・のように続いていきます。
日付の書かれた左から3枚目のシートから最後尾のシートまでの「q3:v11」「x3:x12」「q15:v23」「x15:x24」の範囲を「集計」シートに串刺し演算で合計。ということをしたいと考えています。
日付シートは日々追加されていくのでそのタイミングで実行し集計していく形となります。

発生している問題・エラーメッセージ

エラーメッセージ 「スクリプトによるメソッド Range.getValue の使用頻度が高すぎます」

該当のソースコード

ソースコード function calc_function() { var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets(); const erea1_start = "Q3"; const erea1_end = "V11"; const erea2_start = "X3"; const erea2_end = "X12"; const erea3_start = "Q15"; const erea3_end = "V23"; const erea4_start = "X15"; const erea4_end = "X24"; const erea_start = "Q3"; const erea_end = "X24"; for(var i = 2; i < sheets.length; i++) { for(var col = sheets[i].getRange(erea_start).getColumn(); col <= sheets[i].getRange(erea_end).getColumn(); col++){ for(var row = sheets[i].getRange(erea_start).getRow(); row <= sheets[i].getRange(erea_end).getRow(); row++){ if( ((sheets[i].getRange(erea1_start).getColumn() <= col && col <= sheets[i].getRange(erea1_end).getColumn()) && (sheets[i].getRange(erea1_start).getRow() <= row && row <= sheets[i].getRange(erea1_end).getRow())) || ((sheets[i].getRange(erea2_start).getColumn() <= col && col <= sheets[i].getRange(erea2_end).getColumn()) && (sheets[i].getRange(erea2_start).getRow() <= row && row <= sheets[i].getRange(erea2_end).getRow())) || ((sheets[i].getRange(erea3_start).getColumn() <= col && col <= sheets[i].getRange(erea3_end).getColumn()) && (sheets[i].getRange(erea3_start).getRow() <= row && row <= sheets[i].getRange(erea3_end).getRow())) || ((sheets[i].getRange(erea4_start).getColumn() <= col && col <= sheets[i].getRange(erea4_end).getColumn()) && (sheets[i].getRange(erea4_start).getRow() <= row && row <= sheets[i].getRange(erea4_end).getRow())) ) { if(i == 2){ sheets[0].getRange(row, col).setValue( 0 ); }else{ sheets[0].getRange(row, col).setValue( sheets[0].getRange(row, col).getValue() + sheets[i].getRange(row, col).getValue() ); } } } } } return 0; }

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

macaron_xxx

2018/08/01 00:17

コードは```で囲まれた中に記載してください。現状は「ソースコード」となっている部分です。インデントもきっちりしてくださいね。
hiroshiorz

2018/08/01 02:40

ご指摘ありがとうございます。 分かりづらいようでしたらまた、ご指摘お願いいたします。
guest

回答1

0

ベストアンサー

これが結構早いと思う。(早さに自信はない)

javascript

1function calc_function() { 2 var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets(); 3 4 const erea1_start = "Q3"; 5 const erea1_end = "V11"; 6 7 const erea2_start = "X3"; 8 const erea2_end = "X12"; 9 10 const erea3_start = "Q15"; 11 const erea3_end = "V23"; 12 13 const erea4_start = "X15"; 14 const erea4_end = "X24"; 15 16 var formula = ""; 17 for(var i = 3; i < sheets.length; i++) { 18 if (formula === "") { 19 formula += "="; 20 } else { 21 formula += "+"; 22 } 23 formula += "'" + sheets[i].getSheetName() + "'!R[0]C[0]"; 24 } 25 26 var erea1 = sheets[0].getRange(erea1_start + ":" + erea1_end); 27 var erea2 = sheets[0].getRange(erea2_start + ":" + erea2_end); 28 var erea3 = sheets[0].getRange(erea3_start + ":" + erea3_end); 29 var erea4 = sheets[0].getRange(erea4_start + ":" + erea4_end); 30 31 // 数式でもいい場合は、後ろのsetValuesがいらない。 32 erea1.setFormulaR1C1(formula).setValues(erea1.getValues()); 33 erea2.setFormulaR1C1(formula).setValues(erea2.getValues()); 34 erea3.setFormulaR1C1(formula).setValues(erea3.getValues()); 35 erea4.setFormulaR1C1(formula).setValues(erea4.getValues()); 36}

投稿2018/08/01 06:09

macaron_xxx

総合スコア3191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiroshiorz

2018/08/01 06:19

ありがとうございます!!! とても早いです! ものの2〜3秒で集計できてしまいました。 今、7月の10シート程しかありませんので過去の6月、5月とさかのぼって何ヶ月分までなら同じようなエラーが出ないか見ていきます! そのまま使えるように書き直していただき本当にありがとうございました。
macaron_xxx

2018/08/01 06:29

そもそも、当初発生しているエラーはFor文の中で何度もAPIが呼ばれていたために起こっていたエラーです。 今回のスクリプトは、シートが1つ増えても1回しかAPI呼び出しが増えません。 (formula += "'" + sheets[i].getSheetName() + "'!R[0]C[0]";の部分) なので、相当数のシートでも耐えうると思います。 どちらかというと懸念するポイントとしては、FormulaのLimit(40,000)のほうです。 最大範囲でセル数54なので、54×シート数+[ここ以外の数式に含まれる数式のセル数]が40,000を超えるとOUTなので、2年に近づいてくるとどうか…というところでしょうか。
macaron_xxx

2018/08/01 06:30

と思ったらMAXシート数が200なので、余裕のよっちゃんですね。
hiroshiorz

2018/08/01 06:35

apiの呼び出しが時間がかかりエラーが出ているとわかっていてもそれを省略するすべがわからず困っていました。1回しかapiの呼び出しがないのはかなりの短縮でほんとうにありがたいです! シート200枚・・・ ありがたいです!!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問