Relational Sheets lets you read and write from your database like it's a spreadsheet, with minimal configuration and maintainenance.
I built it because I'm tired of writing the same Django admin code, maintaining complex SQL queries and JavaScript transformers in Retool, and working around the lack of writability in BI tools.
Binaries can be downloaded here:
After downloading, move the file to your "Applications" folder (on Windows)
or run chmod 0777
(on Linux) to make it executable.
Alternatively, compile from source by cloning this repository and
running go build
with go 1.21
or later.
All you need to provide is your database credentials, via enviornment variable:
export DATABASE_URL=postgresql://username:password@host/database
Then run the installed binary to start the server. You can then use it in any browser.
By default, this will run on port 8080. To change ports, set the RS_PORT
environment variable.
Currently only PostgreSQL is supported.
Click Open > + New
to create a new sheet.
This will open a modal where you can select the primary table the sheet should use
and join additional tables. Only tables with foreign keys between them can be joined.
Table names include the database schema—in most cases this will be "public".
Click Insert > Row
to insert a new row in the primary table.
A blank row will appear at the top of the table with an "Add" button below it.
You must enter values for all non-null, non-defaulted columns in the primary table,
but entering values in joined tables is optional. If values are entered in a column
on a joined table, "Add" will attempt to insert a row in the joined table as well
and link it to the primary table via the foreign keys used to join the tables.
Primary key columns are identified by a blue header. Clicking on a primary key cell will allow you to add rows to the other tables in the sheet which will be linked to the selected table, e.g. adding records to a many-to-one relationship. Values can be provided for any tables except the selected table, but the set of tables with values provided must have a path via foreign keys to the selected table.
Click on an individual cell to edit it. Editing is only allowed on tables with primary
keys. The database will be updated when on Enter
or when you click outside
of the cell.
Clicking on a database column header will cycle it between being unsorted, sorted descending, and sorted ascending. It is possible to sort on multiple columns at once, in which case the leftmost column will be the primary sort key and columns to the right will only be used to break ties.
Ctrl+Click
on any column header to hide the column. If you accidentally hide
columns you don't want to, you can unhide all columns by clicking Edit > Show All Columns
.
Hiding a column removes any sorting and filtering on that column.
Hovering over the filter icon at the right of a database column header will allow you to
define a filter on a column. This should be a partial SQL expression, where the column will
be used as the left operand. For example, ">1" will filter the table to only include rows
where that column has a value greater than 1. Filters can be removed by clearing out the
filter input or clicking Edit > Clear All Filters
.
To the right of the database tables you can add spreadsheet columns where you
can enter whatever data you want. Click Insert > Column
to add a column.
Values entered in the cells will be saved. Spreadsheet rows are not tied to database
rows directly. If you wish to maintain the alignment of spreadsheet rows and
database rows as more rows appear in your database, you should put an ascending order
on a sequential ID or timestamp column so that new rows appear at the bottom.
Like Excel, you can perform computations
and reference other columns by entering a formula that begins with =
,
e.g. =A1+B2
will add the values in first cell in column "A" and the second
cell in column "B". Ranges are also supported when used with aggregation functions,
e.g. =SUM(A1:A3)
will return the sum of the first 3 cells in column "A"
and =SUM(A:A)
will return the sum of the entire column.
Use Ctrl+Click
on a cell with a formula in it to fill every cell below it
with the same formula, with rows in cell references intelligently adjusted.
You can also reference cells from your database tables using the same syntax. E.g. if there is column named "foo" in one of your tables, the first cell shown in that table can be referenced as "foo1". If there are multiple columns with the same name, you can distinguish them by using a qualified name, e.g. "mytable.mycolumn" or "public.mytable.mycolumn". Aggregation functions invoked with the whole column as the range will run against every row in the table, even if the sheet is not able to display all rows due to row limits.
Spreadsheet columns support the following functions:
IF(condition, value_when_true, value_when_false)
MAX(values...)
MIN(values...)
SUM(values...)
PRODUCT(values...)
AVERAGE(values...)
COUNTIF(condition_range, condition)
SUMIF(condition_range, condition[, sum_range])
AVERAGEIF(condition_range, condition[, sum_range])
REGEXMATCH(search_string, pattern)
For database columns:
Click
the header to sort by a column or change sorting directionShift+Click
the header to hide a columnClick
a cell in a primary key column (identified by a blue header) to add a child rowClick
any other cell to edit the value in that cell (only possible for tables with primary keys)
Click
the header to rename the columnShift+Click
the header to delete the columnClick
a cell to see and edit its formulaCtrl+Click
a cell to intelligently fill the cells below it with the formula
This project is not accepting outside PRs at this time. However, feature requests are welcome and bug reports are always appreciated!