Drizzle provides you the most SQL-like way to fetch data from your database, while remaining type-safe and composable.
It natively supports mostly every query feature and capability of every dialect,
and whatever it doesn’t support yet, can be added by the user with the powerful sql operator.
For the following examples, let’s assume you have a users table defined like this:
PostgreSQL
MySQL
SQLite
Basic select
Select all rows from a table including all columns:
Notice that the result type is inferred automatically based on the table definition, including columns nullability.
Drizzle always explicitly lists columns in the select clause instead of using select *.
This is required internally to guarantee the fields order in the query result, and is also generally considered a good practice.
Partial select
In some cases, you might want to select only a subset of columns from a table.
You can do that by providing a selection object to the .select() method:
Like in SQL, you can use arbitrary expressions as selection fields, not just table columns:
IMPORTANT
By specifying sql<string>, you are telling Drizzle that the expected type of the field is string.
If you specify it incorrectly (e.g. use sql<number> for a field that will be returned as a string), the runtime value won’t match the expected type.
Drizzle cannot perform any type casts based on the provided type generic, because that information is not available at runtime.
If you need to apply runtime transformations to the returned value, you can use the .mapWith() method.
Conditional select
You can have a dynamic selection object based on some condition:
Distinct select
You can use .selectDistinct() instead of .select() to retrieve only unique rows from a dataset:
In PostgreSQL, you can also use the distinct on clause to specify how the unique rows are determined:
IMPORTANT
distinct on clause is only supported in PostgreSQL.
Advanced select
Powered by TypeScript, Drizzle APIs let you build your select queries in a variety of flexible ways.
Sneak peek of advanced partial select, for more detailed advaced usage examples - see our dedicated guide.
example 1
example 2
example 3
example 4
---
Filters
You can filter the query results using the filter operators in the .where() method:
All filter operators are implemented using the sql function.
You can use it yourself to write arbitrary SQL filters, or build your own operators.
For inspiration, you can check how the operators provided by Drizzle are implemented.
All the values provided to filter operators and to the sql function are parameterized automatically.
For example, this query:
will be translated to:
Inverting condition with a not operator:
You can safely alter schema, rename tables and columns
and it will be automatically reflected in your queries because of template interpolation,
as opposed to hardcoding column or table names when writing raw SQL.
Combining filters
You can logically combine filter operators with and() and or() operators:
Advanced filters
In combination with TypeScript, Drizzle APIs provide you powerful and flexible ways to combine filters in queries.
Sneak peek of conditional filtering, for more detailed advaced usage examples - see our dedicated guide.
example 1
example 2
---
Limit & offset
Use .limit() and .offset() to add limit and offset clauses to the query - for example, to implement pagination:
Order By
Use .orderBy() to add order by clause to the query, sorting the results by the specified fields:
Advanced pagination
Powered by TypeScript, Drizzle APIs let you implement all possible SQL paginations and sorting approaches.
Using the with clause can help you simplify complex queries by splitting them into smaller subqueries called common table expressions (CTEs):
To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query,
you need to add aliases to them:
If you don’t provide an alias, the field type will become DrizzleTypeError and you won’t be able to reference it in other queries.
If you ignore the type error and still try to use the field,
you will get a runtime error, since there’s no way to reference that field without an alias.
Select from subquery
Just like in SQL, you can embed queries into other queries by using the subquery API:
Subqueries can be used in any place where a table can be used, for example in joins:
---
Aggregations
With Drizzle, you can do aggregations using functions like sum, count, avg, etc. by
grouping and filtering with .groupBy() and .having() respectfully, same as you would do in raw SQL:
cast(... as int) is necessary because count() returns bigint in PostgreSQL and decimal in MySQL, which are treated as string values instead of numbers.
Alternatively, you can use .mapWith(Number) to cast the value to a number at runtime.
If you need count aggregation - we recommend using our $count API
Aggregations helpers
Drizzle has a set of wrapped sql functions, so you don’t need to write
sql templates for common cases in your app
Remember, aggregation functions are often used with the GROUP BY clause of the SELECT statement.
So if you are selecting using aggregating functions and other columns in one query,
be sure to use the .groupBy clause
count
Returns the number of values in expression.
countDistinct
Returns the number of non-duplicate values in expression.
avg
Returns the average (arithmetic mean) of all non-null values in expression.
avgDistinct
Returns the average (arithmetic mean) of all non-null values in expression.
sum
Returns the sum of all non-null values in expression.
sumDistinct
Returns the sum of all non-null and non-duplicate values in expression.
max
Returns the maximum value in expression.
min
Returns the minimum value in expression.
A more advanced example:
$count
db.$count() is a utility wrapper of count(*), it is a very flexible operator which can be used as is or as a subquery, more details in our GitHub discussion.
If you need to return a very large amount of rows from a query and you don’t want to load them all into memory, you can use .iterator() to convert the query into an async iterator: