The Table helper in ServiceSQL provides a simple API for managing sheet structures as if they were database tables. This guide covers creating tables, managing columns, and working with table structures.
Creating Tables
Initialize the database
First, initialize ServiceSQL with your spreadsheet ID: const db = APPSQL . init ({ spreadsheetId: "YOUR_SPREADSHEET_ID" });
Get a table reference
Reference a table (sheet) by name: const users = db . table ( "Users" );
Create the table with headers
Use create() to set up your table structure: users . create ([ "id" , "name" , "email" , "age" , "created_at" ]);
Creating Tables with Options
The create() method accepts two parameters:
headers: Array of column names
overwrite: Boolean to replace existing structure (default: false)
Using overwrite: true will clear all existing data in the sheet. Use with caution!
// Create new table
users . create ([ "id" , "name" , "email" ]);
// Overwrite existing table (⚠️ deletes all data)
users . create ([ "id" , "username" , "email" ], true );
Use ensureHeaders() to create tables only if they don’t exist:
// Creates table only if it doesn't exist
users . ensureHeaders ([ "id" , "name" , "email" ]);
// Safe for initialization scripts
function setupDatabase () {
const db = APPSQL . init ({ spreadsheetId: "YOUR_ID" });
db . table ( "Users" ). ensureHeaders ([ "id" , "name" , "email" , "role" ]);
db . table ( "Posts" ). ensureHeaders ([ "id" , "user_id" , "title" , "body" ]);
db . table ( "Comments" ). ensureHeaders ([ "id" , "post_id" , "text" ]);
}
Use ensureHeaders() in initialization scripts to safely set up your database schema without accidentally destroying existing data.
const headers = users . getHeaders ();
Logger . log ( headers ); // ["id", "name", "email", "age"]
The setHeaders() method updates column names while preserving data:
// Rename all headers, preserving data
users . setHeaders ([ "id" , "full_name" , "email_address" , "age" ]);
// With overwrite = true (⚠️ deletes all data)
users . setHeaders ([ "new_id" , "new_name" ], true );
When overwrite is false, setHeaders() intelligently remaps your data to the new column names.
Managing Columns
Adding Columns
Add new columns to the end or at specific positions:
// Add column at the end
users . addColumn ( "phone" );
// Add column at specific position (index 2)
users . addColumn ( "country" , 2 );
// Result:
// ┌────┬──────┬─────────┬───────┬─────┬──────┐
// │ id │ name │ country │ email │ age │phone │
// └────┴──────┴─────────┴───────┴─────┴──────┘
Removing Columns
// Remove a column by name
users . removeColumn ( "phone" );
Removing a column permanently deletes all data in that column. This operation cannot be undone.
Renaming Columns
Rename columns while preserving all data:
// Rename "name" to "full_name"
users . renameColumn ( "name" , "full_name" );
// The data is preserved during the rename
const user = users . findById ( 1 );
Logger . log ( user . full_name ); // Previously stored "name" value
Primary Keys
By default, ServiceSQL uses "id" as the primary key. You can change this:
// Default primary key
users . setPrimaryKey ( "id" );
// Change to another column
users . setPrimaryKey ( "uuid" );
// Now findById, updateById, and deleteById use "uuid"
const user = users . findById ( "abc-123-def-456" );
Table Utilities
Truncating Tables
Remove all data rows but keep the header row:
// Clears all data, keeps structure
users . truncate ();
Dropping Tables
Delete the entire sheet:
// ⚠️ Completely removes the sheet
users . drop ();
drop() permanently deletes the entire sheet. Always confirm before using this operation in production.
Practical Examples
Database Setup
function setupDatabase () {
const db = APPSQL . init ({ spreadsheetId: "YOUR_ID" });
// Create all tables with proper structure
db . table ( "Users" ). create ([
"id" , "name" , "email" , "role" , "created_at"
]);
db . table ( "Posts" ). create ([
"id" , "user_id" , "title" , "body" , "published" , "created_at"
]);
db . table ( "Comments" ). create ([
"id" , "post_id" , "user_id" , "text" , "created_at"
]);
db . table ( "Tags" ). create ([ "id" , "name" ]);
db . table ( "PostTag" ). create ([ "post_id" , "tag_id" ]);
Logger . log ( "Database created successfully" );
}
Schema Evolution
function evolveSchema () {
const db = APPSQL . init ({ spreadsheetId: "YOUR_ID" });
const users = db . table ( "Users" );
// Add new columns for feature expansion
users . addColumn ( "avatar_url" );
users . addColumn ( "is_verified" );
users . addColumn ( "last_login" );
// Rename for clarity
users . renameColumn ( "name" , "full_name" );
// Verify the new structure
const headers = users . getHeaders ();
Logger . log ( "Updated structure:" , headers );
}
Data Migration
function migrateToNewSchema () {
const db = APPSQL . init ({ spreadsheetId: "YOUR_ID" });
// Get data from old table
const oldUsers = db . table ( "UsersOld" );
const oldData = oldUsers . get ();
// Create new table with improved structure
const newUsers = db . table ( "Users" );
newUsers . create ([
"id" , "full_name" , "email" , "age" , "status" , "created_at"
]);
// Migrate and transform data
oldData . forEach ( oldUser => {
newUsers . insert ({
id: oldUser . id ,
full_name: ` ${ oldUser . first_name } ${ oldUser . last_name } ` ,
email: oldUser . email . toLowerCase (),
age: parseInt ( oldUser . age ) || 0 ,
status: "active" ,
created_at: new Date (). toISOString ()
});
});
Logger . log ( `Migrated ${ oldData . length } users` );
// Optional: remove old table after verification
// oldUsers.drop();
}
Safe Table Reset
function safeReset () {
const db = APPSQL . init ({ spreadsheetId: "YOUR_ID" });
const users = db . table ( "Users" );
// Show confirmation dialog
const ui = SpreadsheetApp . getUi ();
const response = ui . alert (
"Confirm Reset" ,
"This will delete all user data. Continue?" ,
ui . ButtonSet . YES_NO
);
if ( response === ui . Button . YES ) {
users . truncate ();
Logger . log ( "Table reset complete" );
} else {
Logger . log ( "Reset cancelled" );
}
}
Best Practices
Define Structure Early
Good Practice Define your complete table structure at creation time: users . create ([ "id" , "name" , "email" , "age" , "status" , "created_at" ]);
Avoid Don’t incrementally add columns as you think of them: users . create ([ "id" , "name" ]);
users . addColumn ( "email" ); // Added later
users . addColumn ( "age" ); // Added even later
Use Proper Primary Keys
// ✅ Set primary key explicitly
users . setPrimaryKey ( "id" );
// Now ID-based operations work correctly
const user = users . findById ( 123 );
users . updateById ( 123 , { name: "Updated" });
users . deleteById ( 123 );
Preserve Data During Changes
// ✅ Rename individual columns
users . renameColumn ( "name" , "full_name" );
users . renameColumn ( "email" , "email_address" );
// ❌ Don't use overwrite with setHeaders
users . setHeaders ([ "id" , "full_name" , "email_address" ], true ); // Loses data!
Confirm Destructive Operations
// ❌ Never do this without confirmation
users . drop ();
// ✅ Always confirm destructive operations
const ui = SpreadsheetApp . getUi ();
if ( ui . alert ( "Delete table?" , ui . ButtonSet . YES_NO ) === ui . Button . YES ) {
users . drop ();
}
Spanish Aliases
ServiceSQL includes Spanish aliases for all table methods:
const usuarios = db . table ( "Usuarios" );
// Create
usuarios . crear ([ "id" , "nombre" , "email" ]);
// Columns
usuarios . crearColumna ( "telefono" );
usuarios . renombrarColumna ( "nombre" , "nombre_completo" );
usuarios . borrarColumna ( "telefono" );
// Headers
const encabezados = usuarios . encabezados ();
usuarios . establecerEncabezados ([ "id" , "nombre_nuevo" ]);
// Utilities
usuarios . establecerClavePrimaria ( "id" );
usuarios . truncar ();
// usuarios.eliminar(); // Same as drop()
Summary
The Table helper provides essential operations for managing your sheet structures:
Creating : create(), ensureHeaders()
Headers : getHeaders(), setHeaders()
Columns : addColumn(), removeColumn(), renameColumn()
Utilities : setPrimaryKey(), truncate(), drop()
For complex queries and data operations, combine Table with QueryBuilder and Models .