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.

FormulasApps ScriptMulti-sheet Setup time: 5 minutes

You'll need: View access to the source spreadsheet. Examples assume an Orders tab with Status in column E.

Formulas

Import a range (first time: click the cell and press Allow access)Formula
=IMPORTRANGE("https://docs.google.com/spreadsheets/d/SOURCE_ID/edit", "Orders!A:F")
Only open orders, selected columns (note Col1, Col2... not letters)Formula
=QUERY(IMPORTRANGE("https://docs.google.com/spreadsheets/d/SOURCE_ID/edit", "Orders!A:F"), "select Col1, Col3, Col6 where Col5 = 'Open'", 1)
Same thing with FILTER (import once, filter by column 5)Formula
=LET(d, IMPORTRANGE("https://docs.google.com/spreadsheets/d/SOURCE_ID/edit", "Orders!A2:F"), FILTER(d, CHOOSECOLS(d, 5)="Open"))
Stack two files with the same columns and drop blank rowsFormula
=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.

  1. Extensions → Apps Script, paste, set the source ID and range.
  2. Run syncSnapshot once (approve access), then installHourlySync.
Code.gsApps Script
/**
 * 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

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.