Recipes / Recipe 10
Pull and filter data from another spreadsheet (IMPORTRANGE + QUERY)
Show only the rows you need from another file, combine several files into one, or take a stable scheduled snapshot.
You'll need: View access to the source spreadsheet. Examples assume an Orders tab with Status in column E.
Formulas
=IMPORTRANGE("https://docs.google.com/spreadsheets/d/SOURCE_ID/edit", "Orders!A:F")=QUERY(IMPORTRANGE("https://docs.google.com/spreadsheets/d/SOURCE_ID/edit", "Orders!A:F"), "select Col1, Col3, Col6 where Col5 = 'Open'", 1)=LET(d, IMPORTRANGE("https://docs.google.com/spreadsheets/d/SOURCE_ID/edit", "Orders!A2:F"), FILTER(d, CHOOSECOLS(d, 5)="Open"))=QUERY({IMPORTRANGE("URL_1", "Orders!A2:F"); IMPORTRANGE("URL_2", "Orders!A2:F")}, "select * where Col1 is not null", 0)Optional: a scheduled snapshot instead of a live link
Lots of IMPORTRANGEs make a sheet slow and can show “Loading…”. This script copies plain values every hour instead.
- Extensions → Apps Script, paste, set the source ID and range.
- Run
syncSnapshotonce (approve access), theninstallHourlySync.
/**
* Optional: copy a range from another spreadsheet as plain values on a schedule.
* Use this instead of IMPORTRANGE when you want a stable snapshot (faster, no "Loading...").
*/
const SYNC_CONFIG = {
sourceId: 'PASTE_SOURCE_SPREADSHEET_ID', // the long id in the source sheet's URL
sourceRange: 'Orders!A1:F',
targetSheet: 'Orders snapshot'
};
/** Pure function: drop fully empty trailing rows that open-ended ranges return. */
function trimEmptyRows(values) {
let end = values.length;
while (end > 0 && values[end - 1].every((v) => v === '' || v === null)) end--;
return values.slice(0, end);
}
function syncSnapshot() {
const cfg = SYNC_CONFIG;
const values = trimEmptyRows(SpreadsheetApp.openById(cfg.sourceId).getRange(cfg.sourceRange).getValues());
const ss = SpreadsheetApp.getActiveSpreadsheet();
const target = ss.getSheetByName(cfg.targetSheet) || ss.insertSheet(cfg.targetSheet);
target.clearContents();
if (values.length) target.getRange(1, 1, values.length, values[0].length).setValues(values);
}
function installHourlySync() {
ScriptApp.newTrigger('syncSnapshot').timeBased().everyHours(1).create();
}
Good to know
- Both ranges in a stacked
{ ; }array must have the same number of columns, or you'll get an error. - Some locales use
\instead of,or;inside array braces. If{A;B}errors, check File → Settings → Locale. - Anyone who can see your sheet can see the imported data, even without access to the source file. Import only what's needed.
Do it yourself
Recipe Club: $12/month
Prefer to set things up yourself? Join the Recipe Club and get access to a private GitHub repository of ready-made, tested automations for Sheets, Apps Script, Python and Node. Each one comes with setup notes and sample data.
- A new recipe added every week
- Everything in the free library, plus the longer, more complete versions
- Use them in your own business as much as you like
- Cancel anytime by email (or the Stripe customer portal once available)
Recipe Club opens soon: join the waitlist
You'll need a free GitHub account. After checkout, reply with your GitHub username and we'll send the repo invite, usually within one business day.
Or buy a one-time recipe pack ($19–$29)
- Clean Data Pack $19
Dedupe, cleaning, merging and normalizing scripts and formulas for messy exports, with a sample sheet.
Coming soon - Forms & Inbox Pack $19
Form auto-replies, request routing, a lead log and follow-up nudges, ready to paste into Apps Script.
Coming soon - Money Ops Pack $29
Invoice reminders, a monthly revenue dashboard with QUERY, a receipts log and nightly backups.
Coming soon
Written with AI assistance. Script logic is unit-tested; formulas follow documented Google Sheets behavior. Always try new automations on a copy of your sheet first.