Pricing

Google Sheets to SQL Server: How to Push Data FROM Sheets INTO Your Database

New Query · Execute · ResultsConnected-- Sales performance reportSELECT fiscal_quarter, SUM(revenue) AS total_revenue, AVG(margin_pct) AS avg_margin, COUNT(order_id) AS order_countFROM dbo.fact_sales WITH (NOLOCK)GROUP BY fiscal_quarter ORDER BY 1;fiscal_quartertotal_revenueavg_marginorder_count2026-Q1$12.4M94.2%4,8122026-Q2$14.1M96.8%5,2402026-Q3$11.8M91.5%4,390(3 rows affected)
JW
James Whitfield

Learn how to push data from Google Sheets into SQL Server using Apps Script JDBC, Python pyodbc, Zapier, or third-party connectors. Includes parameterized queries, batch insert tips, and authentication setup.

The most common question is how to pull SQL Server data into Sheets. But pushing data the other direction (writing from Sheets into your database) is actually searched more often, and for good reason: it's harder to set up correctly.

This guide covers every practical method for writing Google Sheets data into SQL Server, with code examples, authentication requirements, and the SQL injection protections you need before any of this goes near production.

Why Push From Sheets to SQL Server?

There are three practical scenarios where writing from Sheets into SQL Server makes sense:

Data entry staging. Your operations team collects data in Sheets because it is fast and familiar. Once validated, that data needs to live in SQL Server where applications can read it. Rather than exporting a CSV and running a manual import, a push integration makes the handoff automatic.

Bulk updates. Updating hundreds of records in SQL Server directly requires either a database client or a stored procedure. A Sheets-based interface lets non-technical users prepare the update batch, and the integration handles the actual write.

Import pipelines. Finance and ops teams regularly receive data from external vendors in spreadsheet form. Pushing that directly into a staging table in SQL Server removes a manual step from the pipeline.

Authentication Requirements First

Before writing a single line of integration code, you need to sort out how your SQL Server instance accepts connections from outside your network.

SQL Server Authentication vs. Windows Authentication. Apps Script and most cloud tools cannot use Windows Authentication (Kerberos/NTLM). You must create a dedicated SQL Server login with SQL Server Authentication enabled. Keep this account's permissions minimal: only INSERT and UPDATE on the specific tables it needs.

Firewall and network access. If your SQL Server runs on-premises or inside a private VPC, inbound TCP connections on port 1433 from external IPs will be blocked by default. Options:

  • Open port 1433 to the specific IP range used by your integration tool (not recommended for production without an allowlist)
  • Use a VPN or bastion host
  • Mirror data to Azure SQL Database, which is publicly addressable with proper firewall rules

Connection string components you need:

  • Server hostname or IP
  • Port (default 1433)
  • Database name
  • SQL Server login username and password
  • TLS/SSL setting (enforce encrypted connections)

Store credentials in Apps Script Properties Service or environment variables: never hardcode them in script files.

Method 1: Apps Script with JDBC

Apps Script includes a built-in JDBC service that can connect to SQL Server via the jTDS or Microsoft JDBC driver.

Setup:

javascript
function pushSheetsToSQLServer() {
  const props = PropertiesService.getScriptProperties();
  const connString = `jdbc:sqlserver://${props.getProperty('DB_HOST')}:1433;` +
    `databaseName=${props.getProperty('DB_NAME')};` +
    `user=${props.getProperty('DB_USER')};` +
    `password=${props.getProperty('DB_PASS')};` +
    `encrypt=true;trustServerCertificate=false;`;

  const conn = Jdbc.getConnection(connString);
  const sheet = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName('Staging');
  const data = sheet.getDataRange().getValues();
  const headers = data[0];

  // Use parameterized query - never string concatenation
  const stmt = conn.prepareStatement(
    'INSERT INTO dbo.orders (order_id, customer, amount, order_date) ' +
    'VALUES (?, ?, ?, ?)'
  );

  conn.setAutoCommit(false);

  for (let i = 1; i < data.length; i++) {
    const row = data[i];
    stmt.setString(1, row[0]);
    stmt.setString(2, row[1]);
    stmt.setFloat(3, row[2]);
    stmt.setString(4, row[3].toISOString().slice(0, 10));
    stmt.addBatch();
  }

  stmt.executeBatch();
  conn.commit();
  conn.close();
}

Limitations: Apps Script JDBC connections time out after 6 minutes. Do not use this for datasets over roughly 5,000 rows per run. The JDBC service also does not support Windows Authentication.

Method 2: Python + pyodbc

For heavier workloads or more control over error handling, a Python script running on a server or in a cloud function is more reliable than Apps Script.

Install dependencies:

bash
pip install pyodbc gspread oauth2client pandas

Script outline:

python
import pyodbc
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import pandas as pd

# Authenticate to Google Sheets
scope = ['https://spreadsheets.google.com/feeds',
         'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('creds.json', scope)
client = gspread.authorize(creds)

sheet = client.open('My Data Sheet').sheet1
records = sheet.get_all_records()
df = pd.DataFrame(records)

# Connect to SQL Server
conn = pyodbc.connect(
    'DRIVER={ODBC Driver 18 for SQL Server};'
    'SERVER=your-server.database.windows.net;'
    'DATABASE=your_db;'
    'UID=your_user;'
    'PWD=your_password;'
    'Encrypt=yes;TrustServerCertificate=no;'
)
cursor = conn.cursor()

# Parameterized batch insert
insert_sql = '''
    INSERT INTO dbo.staging_orders (order_id, customer, amount)
    VALUES (?, ?, ?)
'''
rows = [(r['order_id'], r['customer'], r['amount']) for _, r in df.iterrows()]
cursor.executemany(insert_sql, rows)
conn.commit()
conn.close()

executemany sends rows in batches and is significantly faster than looping individual execute calls. For very large datasets (100k+ rows), use fast_executemany = True on the cursor.

Method 3: Zapier or Make.com

If you want a no-code setup and can tolerate row-by-row processing rather than bulk operations, Zapier and Make.com both support SQL Server as an action destination.

Zapier setup:

  1. Trigger: "New or Updated Row in Google Sheets" (poll interval: 1–15 minutes)
  2. Action: "Create Row in SQL Server" or "Run Query in SQL Server"
  3. Map Sheets columns to SQL Server fields in the Zap editor
  4. Zapier handles the SQL Server connection; you provide host, port, database, username, and password

Make.com (formerly Integromat) setup:

  1. Trigger: "Watch Rows" in Google Sheets module
  2. Action: "Execute a Query" or "Insert a Row" in SQL Server module
  3. More flexible than Zapier for complex transformations between steps

Limitations: Both platforms process one row per trigger execution. At 100 new rows per day that is manageable; at 10,000 rows it becomes expensive and slow. Neither platform is suitable for bulk historical loads.

Method 4: Third-Party Write-Back Connectors

Tools like Coefficient, Sheetgo, and brooked.io can sync Sheets data to external databases on a schedule. These are best when:

  • You want bidirectional sync (pull data in, edit it, push changes back)
  • The sync should run automatically without maintaining scripts
  • You need a non-technical team member to own the connection

With brooked.io, you configure a Sheets-to-SQL Server sync through a visual interface, set a schedule, and the platform manages authentication tokens, error retries, and sync logs.

Comparison Table

MethodSetup complexityMax rowsNo-codeWrite-back syncCost
Apps Script JDBCMedium~5,000/runNoManualFree
Python + pyodbcHighUnlimitedNoManualServer cost
Zapier / Make.comLow~10k/day practicalYesNo$20–$100+/mo
brooked.ioLowLargeYesYesSubscription

Batch Insert Optimization

Inserting rows one at a time is the most common performance mistake. Every individual INSERT is a round-trip to the database. For 1,000 rows that is 1,000 round-trips.

Use executemany or addBatch. Both Apps Script's JDBC addBatch() and Python's executemany() send a batch of parameterized inserts in a single network call.

Disable autocommit during the batch. Setting conn.setAutoCommit(false) (JDBC) or calling conn.commit() only after the batch avoids transaction overhead on every row.

Use a staging table with a MERGE. Rather than inserting directly into your production table, insert into a staging table first, then run a MERGE statement to upsert records. This is faster and lets you handle duplicates cleanly.

Index considerations. Temporarily disabling non-clustered indexes during a large bulk insert, then rebuilding them afterward, can reduce insert time by 60–80% on large tables.

Preventing SQL Injection

Any integration that writes user-supplied data into SQL Server must use parameterized queries. String concatenation is not acceptable.

Wrong (vulnerable):

javascript
conn.createStatement().execute(
  "INSERT INTO orders VALUES ('" + row[0] + "', '" + row[1] + "')"
);

Right (safe):

javascript
const stmt = conn.prepareStatement(
  'INSERT INTO orders VALUES (?, ?)'
);
stmt.setString(1, row[0]);
stmt.setString(2, row[1]);
stmt.execute();

The database driver handles escaping. You never interpolate user data into the SQL string.

Additional safeguards: validate data types and lengths before the insert, reject rows with unexpected characters in key fields, and run the integration user account with the minimum required permissions.

Troubleshooting

"Connection timed out" or "Cannot open server." The firewall is blocking port 1433. Verify the server's inbound rules allow connections from your integration's IP. For Azure SQL, check the server-level firewall rules in the Azure portal.

"Login failed for user." SQL Server Authentication may be disabled on the instance. Connect with SSMS and verify under Server Properties > Security that "SQL Server and Windows Authentication mode" is selected. Also check that the login account is not locked out.

"Cannot insert duplicate key." Your staging sheet contains rows that already exist in the target table. Add a duplicate check: query existing IDs before inserting, or use INSERT ... WHERE NOT EXISTS or a MERGE statement.

Apps Script JDBC connection fails silently. Add Logger.log(e.toString()) in your catch block. The JDBC error messages are often more specific than the generic exception. Common causes: wrong driver prefix in the connection string, SSL mismatch, or wrong port.

Data type mismatch errors. SQL Server is strict about types. Dates must be formatted as YYYY-MM-DD. Numbers must not contain currency symbols or commas. Validate and clean Sheets data before the insert step.

Bottom Line

Pushing data from Google Sheets into SQL Server is well-supported, but the right method depends on your scale and technical resources. Apps Script JDBC is the lowest-cost option for small datasets and teams with a developer available. Python with pyodbc handles large volumes and complex pipelines. Zapier and Make.com work for non-technical teams pushing modest row counts. Bidirectional sync tools like brooked.io are the best fit when you need the connection managed automatically without ongoing script maintenance.

Whichever method you choose, use parameterized queries, store credentials securely, and test with a staging table before writing to production.

Get Started With brooked.io

brooked.io connects Google Sheets to SQL Server (and dozens of other databases and SaaS tools) with a visual setup, automatic scheduling, and built-in error monitoring, no code required.

Connect Google Sheets to SQL Server with brooked.io →

Related guides:

Troubleshooting quick reference

Frequently asked questions

Can I connect Google Sheets to Azure SQL Database the same way?

Yes. Azure SQL Database uses the same JDBC and ODBC drivers as on-premises SQL Server. The main differences are in the connection string (server address ends in .database.windows.net) and firewall configuration (you add allowed IPs in the Azure portal rather than in a local firewall).

Does Apps Script JDBC work with SQL Server Express?

It works as long as the SQL Server Express instance is reachable over the internet on port 1433. Most Express installations are on local networks without public IP access, which is the more common barrier.

How do I handle duplicate rows when pushing from Sheets?

Use a MERGE statement (SQL Server's upsert syntax). Match on a natural key column, update the record if it exists, insert if it does not. This is safer than trying to deduplicate in the Sheets layer.

Is there a row limit for JDBC batch inserts in Apps Script?

There is no explicit row limit, but the script will time out at 6 minutes. In practice, aim for batches under 2,000–3,000 rows per run. Schedule the script to run multiple times if you need to push larger datasets incrementally.

Can I push to SQL Server from a Google Sheets formula?

No. Formulas are read-only computation. Writes to external databases require a script or integration service.

Ready to connect your data to Google Sheets?

Brooked's free tier covers 100 imports per month with AI Analyst included, no credit card required.

Install Brooked free →

Also in Data Warehouse

More Data Warehouse guides

Data Warehouse

How to Connect Snowflake to Google Sheets

A step-by-step guide to importing Snowflake query results into Google Sheets, scheduling auto-refresh, and writing data back to Snowflake, using Brooked.

JW
James Whitfield
Read
Data Warehouse

How to Connect Databricks to Google Sheets

The official Databricks Connector setup walked from end to end, SQL warehouse selection, Unity Catalog permissions for scheduled refresh, the IP access list gotcha, and the limits table (15-min timeout, 10M cells, 20 schedules), plus Python and no-code alternatives.

JW
James Whitfield
Read

Get your spreadsheet hours back

Brooked sets up in seconds. Your team is querying live data before lunch.

Get started free