High Performance
SQLite
Introduction
Introduction to this course
Introduction to SQLite
SQLite is safe
It's just a file
Running SQLite locally
Good uses for SQLite
SQLite's limitations
The documentation
SQLite Internals
SQLite's structure
SQLite's file format
Dot commands
Pragmas
Virtual tables
Schema
Flexible types
Types
Strict types
Dates
Booleans
Floating point
Rowid tables
Auto increments
Without rowid
Generated columns
Optimizing SQLite
Locking
Rollback mode
WAL mode
WAL vs Journal benchmarks
Busy timeout
Transaction modes
Vacuum
Analyze & Optimize
Suggested pragmas
Faster inserts
Indexes
Introduction to indexes
B+ trees
Primary, secondary, and clustered indexes
Without rowid tables
Benchmarking without rowid tables
Imposter tables
Primary key data types
Where to add indexes
Index selectivity
Composite indexes
Composite ordering
Covering indexes
Partial indexes
Indexes on expressions
Automatic indexes
Duplicate indexes
Indexing joins
Advanced SQL
Explain
Index obfuscation
Joins
Subqueries
Unions
CTEs
Recursive CTEs
Window functions
Dealing with NULLs
Row value syntax
Indexed sorting
Upserts
Returning
Aggregates
Triggers
Operating SQLite
Altering schema
Altering schema with tools
Multi-database
Multi-tenancy
Backups
Exports
How to corrupt SQLite
Advanced JSON
Intro to JSON
JSON vs. JSONB
Argument types: path, value, JSON
JSON5
Valid JSON
Creating JSON objects + arrays
JSON Extraction
Updating JSON
JSON aggregates
JSON table functions
Indexing JSON
Full Text Search
Creating FTS tables
Performing searches
Ranking results
Highlighting matches
Bonus Interviews
DHH discusses SQLite in Ruby on Rails
Distributed SQLite with Litestream and LiteFS
Offline-first, multiplayer SQLite
Production SQLite with Turso and libSQL
Migrating from Postgres to SQLite with Kent C. Dodds
Ruby on Rails with SQLite
Moving from Redis to SQLite with Mike Buckbee
Locked video

Please purchase the course to watch this video.

Video thumbnail
Advanced SQL
Dealing with NULLs

Full Course

$
179
$229
USD, one-time fee
Aaron and Steve are a killer combo for high quality courses like High Performance SQLite. The course shows at great detail the ins and outs of SQLite and how to scale it to compete with any other database. I love it!
Nik Spyratos
Nik Spyratos

SQLite for Production

Build with and integrate SQLite into your production applications.

Test Data

I've made my test data available for you to use and follow along.

Download
or
Use on Turso

Summary

In SQLite, when dealing with missing data represented as nulls, we can compare null values using the "is" and "is not" operators to get definite true or false results. When sorting data, nulls are considered smaller than other values, but you can specify "nulls first" or "nulls last" to control their position in the results. While you can't create an index with null placement, SQLite's sorting flexibility with nulls can help organize your data effectively.

Video Transcript

Oftentimes in your data, you will have values that are missing which we represent as nulls. That much we know. We do need to talk about comparing null values to non null values and sorting null values mixed in with non null values. Let's start with comparing. So if you were to do select 1, that's easy.

We just get 1 back. But if you do select 1 equals null, we get null back. And what this is telling us is that we don't know if this value is true or false. It is simply unknown. It's unknown and it's unknowable because null means a null or not there.

And so when you say is one equal to null, we don't really know. It's an unknown value. It's an unknown value. So instead of saying equal, you can say one is 1 and you get true back. 1 is 0, one is null and you get an actual value back instead of an unknown.

So in other databases there's such thing as like a null safe comparison. The null safe comparison in SQLite is is and is not. So you can do is null or is not null and you get an actual true false back instead of, instead of an unknown value. When it comes to sorting with nulls, nulls are considered small in SQLite. So if we were to do this, select star from categories and we look at that, electronics has no parent ID, so that's a good one.

So we will order by parent ID and we see that the null comes first. And if we were to switch it around to descending, big number comes first, null goes at the very end. So null is smaller than every other value. However, what if you wanted the big numbers at the top, so you didn't wanna switch the whole thing around. You didn't wanna say ascending but you do want the null at the top as well.

You can do that in SQLite, which is very cool. Not all databases support this. You can say nulls first. And you can of course switch it around and say let's go back to ascending, but put the nulls last as well. This is very, very cool.

Can be really helpful but at least you know it exists. You cannot create an index like this though. So if you were to say create index, we'll just call it PID on categories, you could say parent ID ascending. You can create an ascending or descending index. So we'll drop that index drop index PID.

So you could change this to descending. That's fine. And if we were to drop it again, you cannot unfortunately say nulls last. It's invalid or unsupported use of nulls last. So, if you were to create it, parent ID descending and then descending, explain query plan, you'll see it still uses the PID index, but you weren't able to append you weren't able to append that nulls last to the actual index.

So that's just a little bit confusing a little bit confusing to me, but it does look like that index is still being used, even though we have this nulls last on there. And if we were to drop that off, you'll see it's still it's still being used. So I don't know why it doesn't support that, but the ability to control where the nulls end up in your result set is pretty cool and you can do that with nulls first or nulls last.