From: Ardis Lu Date: Thu, 19 Aug 2021 05:57:58 +0000 (-0700) Subject: Initial commit X-Git-Url: https://git.ardis.lu/?a=commitdiff_plain;h=de87e3e8338bf746ab233186ea43a07a128fe52c;p=sheets-db Initial commit --- de87e3e8338bf746ab233186ea43a07a128fe52c diff --git a/Code.gs b/Code.gs new file mode 100644 index 0000000..5fe017e --- /dev/null +++ b/Code.gs @@ -0,0 +1,99 @@ +function onOpen() { + const ui = SpreadsheetApp.getUi(); + ui.createMenu('SQLite') + .addItem('Help', 'showHelp') + .addItem('Generate SQLite database query', 'generateDatabaseQuery') + .addToUi(); +} + +function showHelp() { + const helpMessage = `Welcome to sheets-db! + +USAGE: +- Edit the data on this workbook like you would on any other Google Sheet, noting KEY ASSUMPTIONS below. +- When ready, press the "Generate SQLite database query" button to generate a SQL query which can be used to write a SQLite database containing this workbook's data! + +KEY ASSUMPTIONS: +- Each tab in this workbook is a data table +- The first row specifies the SQLite data type for the column (i.e. it is not part of the dataset) +- The second row is a header row (i.e. it is not part of the dataset) +- Every other row is part of the dataset +- All dataset values are valid +- There are no empty rows or empty columns`; + + const ui = SpreadsheetApp.getUi(); + ui.alert('Help', helpMessage, ui.ButtonSet.OK); +} + +function generateDatabaseQuery() { + /** + * KEY ASSUMPTIONS: + * - Each tab in this workbook is a data table + * - The first row specifies the SQLite data type for the column (i.e. it is not part of the dataset) + * - The second row is a header row (i.e. it is not part of the dataset) + * - Every other row is part of the dataset + * - All dataset values are valid + * - There are no empty rows or empty columns + */ + + const sheets = SpreadsheetApp.getActive().getSheets(); + const fileId = '1xUrGGbaQLVRnytUKtnINAxzild0PBeJZ'; // Google Drive file ID to store the final SQL query + + /** Construct SQL for creating the database */ + let query = `-- This query was generated by sheets-db +-- https://docs.google.com/spreadsheets/d/1pY-0oDh4pI8NffZQwN-AkpfJdot7bmlM9nky7w150UY/ +`; + for (let sheet of sheets) { + const tableName = sheet.getSheetName(); + const dataset = sheet.getDataRange().getValues(); // Assuming there are no empty rows or empty columns + const datatypes = dataset.shift(); + const headers = dataset.shift(); + + // Headers + let columns = ''; + for (let i = 0; i < headers.length; i++) { + columns += `'${headers[i]}' ${datatypes[i]},`; + } + columns = columns.slice(0, -1); // Remove trailing comma from the last header + + // Values + let values = ''; + for (let row of dataset) { + values += '('; + + for (let col = 0; col < row.length; col++) { + switch (datatypes[col]) { + case 'INTEGER': + case 'REAL': + values += `${row[col]},`; + break; + case 'TEXT': + case 'BLOB': + values += `'${row[col].toString().replace(/'/g, "''")}',`; // Escape apostrophe with double aprostophe + break; + case 'NULL': + default: + values += 'null,'; + break; + } + } + values = values.slice(0, -1); // Remove trailing comma from the last value + + values += '),'; + } + values = values.slice(0, -1) + ';'; // Replace the final comma with a semicolon + + // Insert the query to generate this data table + query += ` + CREATE TABLE ${tableName} (${columns}); + INSERT INTO ${tableName} VALUES ${values} + `; + } + + // URL to download the file: + // https://drive.google.com/u/0/uc?id=1xUrGGbaQLVRnytUKtnINAxzild0PBeJZ&export=download + DriveApp.getFileById(fileId).setContent(query); + + const ui = SpreadsheetApp.getUi(); + ui.alert('Success!', `Query generated! Download here: https://drive.google.com/u/0/uc?id=${fileId}&export=download`, ui.ButtonSet.OK); +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..f6a19ce --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# sheets-db + +Minimal Google Apps Script (GAS) project intended to quickly transform a Google Sheet into a SQLite database. + +Demo here (create a copy of the Google Sheet): https://docs.google.com/spreadsheets/d/1pY-0oDh4pI8NffZQwN-AkpfJdot7bmlM9nky7w150UY/edit?usp=sharing + +NOTE: you must update the hardcoded Google Drive file ID in the GAS code (see setup below), otherwise the demo will not work. + +# Requirements +- A Google Drive file that can be overwritten with the Google Apps Script output +- A Google Sheet to attach this Google Apps Script project to +- A SQLite client to execute the resulting SQL query + +# Initial setup + +These steps only need to be completed once. + +## Setting up the Google Drive file + +1. Upload any file to Google Drive. The content of this file will be overwritten later. Name the file something relevant, like `generateDatabaseQuery.txt`. +2. In Google Drive, right click > get link and note the file's ID (the ID should look like this: `1xUrGGbaQLVRnytUKtnINAxzild0PBeJZ`). + +## Setting up the Google Sheet + +3. Create a new Google Sheet or create a copy of the [demo Google Sheet](https://docs.google.com/spreadsheets/d/1pY-0oDh4pI8NffZQwN-AkpfJdot7bmlM9nky7w150UY/edit?usp=sharing). +4. Go to Tools > Script Editor to create a new Google Apps Script (GAS) project. The GAS project is automatically attached to the Google Sheet. +5. Copy `Code.gs` into the GAS project and save. If you copied the demo Google Sheet, this code should already be there. +6. **(IMPORTANT)** In `Code.gs`, update the hardcoded constant `fileId` to the file ID noted in Step 2. + +# Usage + +1. Refresh the Google Sheet to load the GAS code. +2. See the new custom menu button `SQLite`. Press `SQLite > Help` for end-user instructions. +3. Press `SQLite > Generate SQLite database query` to generate the database generation SQL query. +4. In your favorite SQLite client (example: [sqliteviz](https://lana-k.github.io/sqliteviz/#/workspace)), paste in the SQL query and run it.