SQLite

Storage Classes

Booleans are stored using INTEGER (0,1) Date and Time are stored as one of - TEXT - REAL - INTEGER

NVARCHAR(x bytes) has affinity to TEXT, and is only accepted to be SQL-compatible. That is, SQLITE doesn’t care, and will allow storage of more than x bytes there.

Date and time

Statements

Order of execution of Clauses i.e FROM > WHERE > GROUP BY > HAVING > DISTINCT > SELECT > ORDER BY

Create

CREATE TABLE IF NOT EXISTS table_name(
    column_1 TEXT NOT NULL,
    column_2 TEXT NOT NULL,
    column_3 REAL DEFAULT 0,
    PRIMARY KEY(column_1, column_2))
    [WITHOUT ROWID]; -- optional

Insert

INSERT INTO table (column1,column2 ,..)
VALUES
    (value1, value2, ...),
    (value1, value2, ...);

Update

Replace

INSERT OR REPLACE INTO table(column_list)
VALUES(value_list);

-- or shorter

REPLACE INTO table(column_list)
VALUES(value_list);

Select

https://www.sqlite.org/lang_select.html

SELECT DISTINCT column_list
FROM table
JOIN table2 on join_condition
WHERE row_filter1 AND/OR row_filter2 --...
GROUP BY column
HAVING group_filter
ORDER BY column ASC/DESC
LIMIT count OFFSET offset
;

WHERE operators

Only use HAVING where you cannot put the condition on a WHERE ... GROUP BY tracks.albumid HAVING COUNT(trackid) > 15

SQL Aliases

SELECT t.col as c
FROM table as t1, table as t2
WHERE t1.col1 = t2.col2

Queries with expressions

SELECT col / 2.0 AS half
FROM table

Subqueries

A SELECT statement within the WHERE or HAVING clause of an INSERT, UPDATE, MERGE, or DELETE statement.

select col
from table
where table.id not in
( select id from table2 );

These are less efficient than joins.

Functions

MIN MAX AVG ROUND(x,n) COUNT

Clauses

Joins

A JOIN clause is used to combine rows from two or more tables, based on a related column between them.

SELECT *
FROM Orders
INNER JOIN
    Customers
ON Orders.CustomerID=Customers.ID;

All the OUTER JOINs return NULL when no matching value.

Joins tend to take more memory than other queries (WHERE, HAVING etc).

Index

Each index (a B-tree) must be associated with a specific table. An index consists of one or more columns (from the same table). A table may have multiple indexes.

Performance

If queries are infrequent or if there is a connection pool then it is possibly better to open a connection as late as possible, and to close it as early as possible. This allows the connection to return to the connection pool. Note that connection pooling is handled by the database driver. Overall, this is expected to reduce memory requirements. SQLite is not great at concurrency.

Otherwise, keeping the connection open is a factor of 3 to 8 times faster. But since the cost of opening and closing connections on SQLite is very small (the db is local), this likely does not matter.

WAL mode

Uses a write-ahead log (i.e. append only) which is then batch processed. - performs better - allows for concurrent read access

https://sqlite.org/wal.html

PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;

Note: - journal_mode is persistent - synchronous only applies per connnection

Synchronous flag is usually FULL or NORMAL. FULL fsyncs to ensure transactions are durabile. In WAL mode, NORMAL is sufficient: exchanges speed (fsync calls) for durability without risking data corruption. This mode will ensure that the fsync() calls are only called when the WAL becomes full and has to checkpoint to the main database file.

Other possibilities

No RowId

A rowid stores an 8-byte int to uniquely identify a row in a table. Specifying WITHOUT ROWID, in SQLite, can reduce storage and processing requirements.

Usually, the key is used to look up the rowid which indexes into disk to fetch the value. Without a rowid, the key becomes the index.

We thus need a primary key (and not integer primary keys!). Also, to gain performance from using this, no row should be more than 5% of the size of the database page.

Functions

select count(distinct ColName) from Table

Date and time functions

Examples

Miscellenaeous

Can dump table as sql using .dump in the CLI.

The SQL standard says that strings must use ‘single quotes’, and identifiers (such as table and column names), when quoted, must use “double quotes”.

References

TODO https://duckdb.org/docs/sql/introduction